{"id":25019735,"url":"https://github.com/donghl-dev/project-todolist","last_synced_at":"2026-04-09T07:03:14.523Z","repository":{"id":126966253,"uuid":"174999198","full_name":"donghL-dev/Project-ToDoList","owner":"donghL-dev","description":"To Do List Web Application using Spring Boot","archived":false,"fork":false,"pushed_at":"2023-03-15T11:35:35.000Z","size":2407,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-21T00:42:45.428Z","etag":null,"topics":["gradle","jdk8","jpa-hibernate","junit4","mysql","spring-boot","spring-mvc","spring-security","thymeleaf"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/donghL-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-03-11T12:51:01.000Z","updated_at":"2023-03-15T11:35:40.000Z","dependencies_parsed_at":"2023-06-19T09:54:28.045Z","dependency_job_id":null,"html_url":"https://github.com/donghL-dev/Project-ToDoList","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/donghL-dev/Project-ToDoList","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donghL-dev%2FProject-ToDoList","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donghL-dev%2FProject-ToDoList/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donghL-dev%2FProject-ToDoList/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donghL-dev%2FProject-ToDoList/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/donghL-dev","download_url":"https://codeload.github.com/donghL-dev/Project-ToDoList/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/donghL-dev%2FProject-ToDoList/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28133050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-30T02:00:05.476Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gradle","jdk8","jpa-hibernate","junit4","mysql","spring-boot","spring-mvc","spring-security","thymeleaf"],"created_at":"2025-02-05T11:51:29.912Z","updated_at":"2025-12-30T22:07:02.735Z","avatar_url":"https://github.com/donghL-dev.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Prjoect - To Do List\n===\n* Spring Boot를 이용하여 Web에서 동작 가능한 To Do List를 구현하기 위한 프로젝트입니다.\n\n* 이 저장소는 To Do List Web Application을 개발하면서 소스코드 관리 및 버전관리를 위한 저장소입니다.\n\n* 목적\n  \n  * Spring Boot \u0026 JPA 학습 및 Web Application(To Do List) 개발.\n\n  * Spring Security 학습 및 로그인, 회원가입 구현.\n\n  * JUnit 프레임워크를 이용하여 프로젝트 내에서 테스트 해야할 케이스들의 테스트 코드 작성 및 학습.\n\n## 개발환경\n\n|도구|버전|\n|:---:|:---:|\n| Framework |Spring Boot 2.1.3 |\n| OS |Windows 10|\n|IDE |IntelliJ IDEA Ultimate |\n|JDK |JDK 1.8|\n|DataBase |MySQL Server 5.7|\n|Build Tool |Gradle 5.2.1|\n\n## 실행 방법\n\u003cdetails\u003e\u003csummary\u003e세부정보\u003c/summary\u003e\n\n* 준비사항.\n    \n    * Gradle or IntelliJ IDEA\n\n    * JDK (\u003e= 1.8)\n\n    * Spring Boot (\u003e= 2.x)\n\n* 저장소를 `clone`\n\n    ```bash\n    $ git clone https://github.com/donghL-dev/Project-ToDoList.git\n    ```\n* 프로젝트 내 Project-Matching\\src\\main\\java\\com\\matching\\config 경로에 `HttpConfig.java` 삭제 또는 내용 주석처리.\n\n* DB는 MySQL을 쓴다고 가정.\n\n    * 다른 DB를 사용한다면, 그 DB에 맞게 설정을 해야함.\n\n* 프로젝트 내 src\\src\\main\\resources 경로에 `application.yml` 생성.\n\n    * 밑의 양식대로 내용을 채운 뒤, `application.yml`에 삽입.\n    \u003cbr\u003e\n\n    ```yml\n    spring:\n        datasource:\n            url: jdbc:mysql://localhost/본인_DB\n            username: 본인_DB_User\n            password: 본인_DB_User_Password\n            driver-class-name: com.mysql.jdbc.Driver\n        jpa:\n            hibernate:\n            ddl-auto: create\n    ```\n\n* IntelliJ IDEA(\u003e= 2018.3)에서 해당 프로젝트를 `Open`\n\n    * 또는 터미널을 열어서 프로젝트 경로에 진입해서 다음 명령어를 실행.\n\n    * Windows 10\n\n        ```bash\n        $ gradlew bootRun\n        ```\n\n    * Ubuntu 18.04\n\n        ```bash\n        $ ./gradlew bootRun\n        ```\n\n\u003c/details\u003e\n\n## 주요기능 \n\n * [확인](https://github.com/dongh9508/Project-ToDoList/tree/master/image/MainFunction)\n\n## 개발과정\n\u003cdetails\u003e\u003csummary\u003e세부정보\u003c/summary\u003e\n\n### project-day-1 \n\n  * Spring-Boot-Web-TDL 프로젝트 생성.\n\n  * ToDoList 클래스 설계 및 생성.\n\n    * Idx(키) -\u003e Integer\n\n    * Description(내용) -\u003e String\n\n    * Status(완료 여부) -\u003e Boolean\n\n    * CreatedDate(생성 시간) -\u003e LocalDateTime\n\n    * CompletedDate(완료 시간) -\u003e LocalDateTime\n\n\n### project-day-2\n\n  * 프로젝트 패키지 생성.\n\n    * 도메인, 컨트롤러, 서비스, 레포지토리 패키지 생성.\n\n  * 프로젝트와 MySQL 연동 및 테스트\n\n    * application.yml 및 build.gradle 수정\n\n    * MySQL DB에 데이터 삽입 및 [확인.](./image/1.png)\n\n  * 서비스 호출 및 뷰 반환을 위한 ToDoListController 클래스 생성.\n\n  * 저장소 호출 및 데이터 반환을 위한 ToDoListService 클래스 생성.\n\n  * 데이터를 보여주기 위한 list.html 생성\n\n    * 부트 스트랩을 이용해서 뷰 꾸미기.\n    \n    * 부트 스트랩을 Spring 프레임워크에서 사용시에 경로 매핑을 주의해야함.\n\n        * CSS 적용 시, 경로는 /static/css가 아니라 /css로 경로 설정해야 함.\n\n            * `\u003clink rel=\"stylesheet\" href=\"/css/bootstrap.min.css\"/\u003e`\n    \n    * 부트스트랩을 활용한 뷰 [확인](./image/2.png)\n\n  * IntelliJ IDEA 와 MySQL [연동](./image/3.png)\n\n\n### project-day-3\n\n  * View 수정 및 [업데이트](./image/4.png)\n\n\n### project-day-4\n\n  * View 수정 및 업데이트\n\n    * css 설정 값 추가 및 수정 \n    \n    * Header와 Footer 생성.\n\n\n### project-day-5\n\n  * to do list 목록의 CRUD를 위한 ToDoListRestController 클래스 생성.\n\n    * to do list 목록의 생성을 위한 값을 View에서 Input을 통해 받아옴.\n\n    * 받아온 Input값을 postToDoList 메소드를 통해서 및 PostMapping으로 url 매핑 처리후 ToDoListService에서 로직 처리.\n\n    * ToDoListService에서 로직을 통해 DB에 값을 저장 한 뒤 View가 Redirect 된 후 저장된 목록 출력.\n\n\n### project-day-6\n\n  * to do list 목록의 삭제 기능과 상태와 내용 업데이트 기능 구현\n\n    * 삭제를 하기 위해서 @PathVariable를 통해서 idx 값을 받아온 뒤 DeleteMapping으로 매핑시킨 뒤, deleteToDoList 메소드를 생성해서 로직 처리.\n\n    * 상태와 내용 업데이트를 위해서  @PathVariable를 통해서 idx 값을 받아온 뒤 PutMapping으로 매핑시킨 뒤, putDescription, putStatus 메소드를 생성해서 로직 처리.\n\n  * 기존의 View에서 [업데이트](./image/5.png)\n\n\n### project-day-7\n\n  * User 모델과 ToDoList 모델 1 : 1 관계 설정.\n\n  * User 도메인 클래스 생성\n\n    * Idx(키) -\u003e Integer\n\n    * Name(이름) -\u003e String\n\n    * Email(이메일) -\u003e String\n\n    * Password(비밀번호) -\u003e String\n  \n  * 기존의 ToDoList 클래스에 User 컬럼 추가.\n\n    ```java\n    @OneToOne(fetch = FetchType.LAZY)\n    private User user;\n    ```\n\n  * User 객체 생성 후 MySQL DB에 데이터 삽입.\n\n    * CommandLineRunner를 이용해서 생성 로직 처리.\n\n  * User 객체를 이용하기 위해서 Controller, Repository, Service 클래스 생성.\n\n  * ToDoListController 클래스와 ToDoListRestController의 수정을 통해서 User 객체 값 [저장](./image/6.png).\n\n\n### project-day-8\n\n  * 로그인 기능 구현\n\n    * 로그인 관련 처리를 위한 LoginController 클래스 생성\n\n    * 로그인 뷰 [생성](./image/7.png).\n\n  * 회원가입 기능 구현\n\n    * 회원가입 관련 처리를 위한 RegisterController 클래스 생성\n\n    * 회원가입 뷰 [생성](./image/8.png).\n  \n  * 회원가입 확인\n\n    * Username, Email, Password Ajax 객체 생성 후, 데이터 전송.\n\n    * 필요한 값을 받아와서 회원가입 로직을 통해 유저에 필요한 값을 저장 후, 유저 [생성](./image/9.png).\n\n  * 로그인 확인\n\n    * Username, Password Ajax 객체 생성 후, 데이터 전송.\n\n    * loginUser 함수 생성 후, 필요한 값을 받아온 후 로그인 체크.\n\n      * Username이 존재하지 않을 경우, 로그인 실패.\n\n      * Username이 존재할 경우, password가 일치 하지 않을시 로그인 실패.\n\n      * Username이 존재할 경우, password가 일치하다면 로그인 성공.\n\n\n### project-day-9\n\n  * 로그인을 하지 않고 To Do List url로 이동할 경우, 로그인 화면으로 redirect 되도록 설정.\n\n  * To Do List에 현재 로그인을 한 유저가 등록한 To Do 항목과 Complete 항목이 보이도록 설정.\n\n  * To Do가 등록될 때, DB의 To Do List의 테이블에도 현재 로그인 한 유저의 Idx가 [저장](./image/tododb.png)됨.\n\n\n### project-day-10\n\n  * User 모델 객체와 ToDoList 모델 객체간 관계를 단방향 관계에서 양방향 관계로 재설정.\n\n    * `@OneToMany` 어노테이션과 `@ManyToOne` 어노테이션을 사용하여 관계성 재설정.\n\n    * Foreign Key를 가지고 있고 OwnerShip을 가지고 있는 모델 객체에 `@ManyToOne` 어노테이션을 사용.\n\n    * OwnerShip을 가지고 있지 않은 모델 객체에 `@OneToMany` 어노테이션을 사용.\n\n    * `@OneToMany`를 사용한 모델 객체에 `@OneToMany` 어노테이션의 속성 중 하나인 mappedby로 OwnerShip을 가지고 있는 객체의 변수명을 기입한다.\n\n    * OwnerShip을 가지고 있지 않은 모델 객체에는 OwnerShip을 가지고 있는 모델 객체로 된 필드를 Collection 자료형으로 선언한다.\n\n  * ToDoList 모델에 `@ManyToOne` 어노테이션을 사용하고, User 모델에 `@OneToMany` 어노테이션을 사용해서 N : 1 양방향 관계로 설정.\n\n  * 테이블 및 코드 [확인](https://github.com/dongh9508/Project-ToDoList/tree/master/image/RelationShip)\n\n\n### project-day-11\n\n  * 현재 User가 자신이 등록한 ToDoList를 가지고 있어야 한다.\n\n  * User 도메인 클래스의 `@OneToMany` 어노테이션의 속성으로 FetchType을 EAGER로 설정한다.\n\n  * User 도메인 클래스에 있던 List\u003cToDoList\u003e todolists 필드에 현재 유저가 작성한 ToDoList 목록을 넣기 위해 ArrayList로 생성한다.\n\n  * User 도메인 클래스의 List\u003cToDoList\u003e todolists 필드에 현재 유저가 작성한 ToDoList 목록을 넣기 위한 add 메소드 생성.\n\n    ```java\n    public class User {\n      \n      ...\n      ...\n      ...\n\n      @OneToMany(mappedBy = \"user\", fetch = FetchType.EAGER)\n      private List\u003cToDoList\u003e toDoLists = new ArrayList\u003c\u003e();\n\n      ...\n      ...\n\n      public void add(ToDoList toDoList) {\n        toDoList.setUser(this);\n        this.toDoLists.add(toDoList);\n      }\n    }\n    ```\n\n\n### prjoect-day-12\n\n  * /list url로 redirect 될 때마다 콘솔에 현재 User의 Idx와 User가 가지고 있는 ToDoList들의 객체들을 출력.\n\n  * Spring Security 적용을 위한 테스트 프로젝트 생성.\n\n    * Spring Security를 위한, 의존성 설정.\n\n      ```java\n      dependencies {\n        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'\n        implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'\n        implementation 'org.springframework.boot:spring-boot-starter-web'\n        compile 'org.springframework.security:spring-security-web:4.2.7.RELEASE'\n        compile 'org.springframework.security:spring-security-config:4.2.7.RELEASE'\n        compileOnly 'org.projectlombok:lombok'\n        runtimeOnly 'org.springframework.boot:spring-boot-devtools'\n        runtimeOnly 'com.h2database:h2'\n        runtimeOnly 'mysql:mysql-connector-java'\n        testImplementation 'org.springframework.boot:spring-boot-starter-test'\n      }\n      ```\n    \n    * application.yml 설정.\n\n      ```java\n      server:\n        port: 8080\n\n      logging:\n        level:\n          root: WARN\n          org.springframework.web: INFO\n          org.springframework.security: INFO\n\n      spring:\n        thymeleaf:\n          cache: false\n      ```\n\n    * templates에 필요한 index.html, login.html, user/index.html 생성.\n\n    * 스프링 시큐리티를 이용한 로그인을 위한 코드 작성.\n\n      * MainController 클래스 생성.\n\n      * SecurityConfig 클래스 생성.\n\n        * SecurityConfig 클래스에 WebSecurityConfigurerAdapter 클래스를 상속받고, `@EnableWebSecurity` 어노테이션을 적용함.\n\n        * configure() 메소드와, configureGlobal() 메소드 작성.\n\n          * configureGlobal() 메소드의 인메모리 인증 코드 부분의 password 부분을 인코딩 해주지 않아서 에러가 일어남.\n\n          * PasswordEncoder 클래스를 이용해서 인코딩 에러가 일어나는 부분을 해결.\n\n\n### prjoect-day-13\n\n  * day-12에서 생성한 프로젝트에서 [GUIDE](https://spring.io/guides/gs/securing-web)를 통해 코드 실습 진행.\n\n  * 템플릿에 `home.html` 과 `hello.html` 를 생성하고, MvcCofig 클래스를 생성.\n\n  * MvcConfig 클래스를 생성한 뒤에, `@Configuration` 어노테이션을 붙여주고, `WebMvcConfiguer` 인터페이스를 상속받는다.\n\n  * 그 이후, `addViewController(ViewControllerRegistry registry)` 메소드를 오버라이딩 한 뒤, registry에 `ViewController`를 추가한다.\n\n    * `registry.addViewController(\"/home\").setViewName(\"home\");`\n\n    * /home url로 이동했을 때, `home`이라는 이름의 view name을 가진 `home.hml`로 매핑해주는 방식이다.\n\n    * 그 밖에 다른 ViewController도 추가한다.\n\n  * 그 이후, 스프링 시큐리티 의존성을 추가하고, 실행해보면 모든 페이지가 잠금이 걸린다.\n\n  * 시큐리티 설정을 위한 WebSecurityConfig 클래스를 생성하고 WebSecurityConfigurerAdapter 클래스를 상속받는다.\n\n    * WebSecurityConfig 클래스에 `@Configuration` 어노테이션과 `@EnableWebSecurity` 어노테이션을 사용한다.\n\n    * `@EnableWebSecurity` 어노테이션을 사용하는 순간, 스프링 부트가 제공하는 스프링 시큐리티 설정을 따라간다고 가정한다.\n\n    *  WebSecurityConfig 클래스에 HttpSecurity를 파라미터로 갖는 configure() 메소드 오버라이딩.\n\n      * `.authorizeRequests()` 은 요청에 대해 어떻게 보안을 걸 것인가에 대한 설정 메소드이다.\n\n      * `.antMatchers()` 는 특정한 패턴에 대한 요청들의 처리하기 위한 설정값이다.\n\n      * `.antMatchers().permitAll()` 는 `.antMatchers()`로 지정된 패턴에 대한 요청들은 전부다 허용하라는 의미이다.\n\n        * `.antMatchers(\"/\", \"/home\").permitAll()` / 와 /home에 대해서는 전부 허용하라, 로그인을 안한 사용자에게도 보이도록 설정.\n\n      * `.anyRequest().authenticated()` 이외의 요청들은 인증이 필요한 요청이라, 인증된 사용자만 가능하다는 의미.\n\n      * `.formLogin()` 속성은 Login에 관한 속성이다. `.anyRequest().authenticated()` 속성으로 인해서 이외의 요청들은 formLogin으로 설정된 loginPage로 이동.\n\n      * `.loginPage()` 은 loginPage로 가는 Url이 어떤것인가에 대한 설정이다.\n      \n      * `.logout()` 메소드는 로그아웃에 대한 속성 값에 대한 설정이다.\n\n        * `.logoutUrl()` 메소드는 로그아웃시 Redirect 되는 Url을 결정한다.\n\n    * WebSecurityConfig 클래스에 userDetailsService() 메소드 오버라이딩.\n\n      * UserDetails 클래스를 통해 user 생성.\n\n        * `.withDefaultPasswordEncorder()` 속성을 통해 패스워드 인코딩 설정.\n\n        * `.userName()` 을 통해 user 이름 설정.\n\n        * `.password()` 을 통해 패스워드 설정\n\n        * `.roles()` 을 통해 권한 설정.\n\n        * InMemoryUserDetailsManager 클래스를 통해 인 메모리에 유저를 저장.\n\n    * `login.html` 생성\n\n    * `hello.html` 코드 변경, 로그인된 사용자의 정보 표시 및 로그아웃 버튼 생성.\n\n    * 결과\n\n      * 로그인을 하기전까지는 `/` 과 `/home` 과  `/loign` url만 접근 가능.\n\n      * 로그인을 하기전까지는 허용된 url 이외의 url 접근시, `/loign` url로 Redirect\n\n      * 로그인을 성공하면, 기존에 `/home`에서 이동하고자 했던, `/hello` url로 접근할 수 있다.\n\n      * 로그아웃을 하면, 다시 `/login` url로 돌아간다.\n\n      * 즉, 스프링 시큐리티를 통해서 로그인을 성공시키면, 유저는 인증된 사용자가 되고, 인증된 사용자가 가질수 있는 권한을 가지게 된다.\n\n      * 위 코드는 인증된 사용자에게 `/home` 으로 접근을 할 수 있게 하는 권한을 부여하였다.\n\n\n### prjoect-day-14\n\n  * [GUIDE](https://spring.io/guides/gs/securing-web)를 통해 진행했던 실습 코드를 수정 및 리팩토링.\n\n  * 지난 코드 내용 [리뷰](https://github.com/dongh9508/Project-ToDoList/tree/master/image/SECREVIEW)\n\n  * 이전에 진행했던 UserDetails 클래스를 통해서 인 메모리에 유저를 저장했던 방식은 테스트 코드에서 주로 쓰이는 방식.\n\n  * 현실적인 User를 생성하기 위해서 이전 코드에서 UserDetails 클래스 코드 부분 제거.\n\n  * AccountController, AccountService, AccountRepository 생성.\n\n  * AccountService 클래스에서 UserDetailsService 인터페이스를 상속받는다.\n\n    * `loadUserByUsername()` 메소드를 오버라이딩한다.\n\n      * `loadUserByUsername()` 메소드에서 파라미터로 받은 username으로 Account를 레포에서 찾아오고, 찾아온 Account를 UserDetalis 인터페이스로 변환한다.\n\n      * Account는 현재 프로젝트만의 도메인이므로, 스프링 시큐리티는 이 도메인을 알 수가 없기 때문에, 스프링 시큐리티가 알 수 있도록 UserDetalis 인터페이스로 변환한다.\n\n      * UserDetalis 객체가 생성된 코드.\n\n        ```java\n        UserDetails userDetails = new UserDetails() {\n            @Override\n            public Collection\u003c? extends GrantedAuthority\u003e getAuthorities() {\n                return null;\n            }\n\n            @Override\n            public String getPassword() {\n                return null;\n            }\n\n            @Override\n            public String getUsername() {\n                return null;\n            }\n\n            @Override\n            public boolean isAccountNonExpired() {\n                return false;\n            }\n\n            @Override\n            public boolean isAccountNonLocked() {\n                return false;\n            }\n\n            @Override\n            public boolean isCredentialsNonExpired() {\n                return false;\n            }\n\n            @Override\n            public boolean isEnabled() {\n                return false;\n            }\n        }\n        ```\n      * ROLE에 관한것을 원래는 따로 만들어야 하나, 간단하게 UserDetails 안에 ROLE을 만들어서 처리함.\n\n      * User를 생성하기 위해서 WebSecurityConfig 클래스에서 `/careate` url도 인증없이 접속할 수 있도록 수정.\n\n      * 프로젝트 빌드 후, `/create` url로 이동하면, 생성된 계정을 [확인](./image/22.png)이 가능하다.\n\n        * 해당 url로 이동했을 때, 패스워드가 그대로 노출되기 때문에 문제가 됨. 이런식으로 해선 안됨.\n\n      * 확인된 계정으로 로그인을 하더라도, 콘솔 로그창에 에러가 출력되면서 로그인이 되지 않음.\n\n        * 에러를 확인해본 결과, password 인코딩 문제가 에러의 원인이 됨.\n\n        * 해결을 위해선 WebSecurityConfig 클래스에 PasswordEncoder 타입의 passwordEncoder() 메소드를 `@Bean`으로 등록.\n\n          ```java\n          @Bean\n          public PasswordEncoder passwordEncoder() {\n              return PasswordEncoderFactories.createDelegatingPasswordEncoder();\n          }\n          ```\n        * AccountService 클래스에서 account의 패스워드를 불러와서 PasswordEncoder 클래스를 통해서 인코딩을 거친 후 저장.\n      \n      * 프로젝트 재빌드 후, `/create` url로 이동하면, 생성된 계정의 패스워드가 인코딩 된 것을 [확인](./image/23.png)할 수 있다.\n\n      * 인코딩을 거친 후에는 로그인 시에 콘솔에 나타났던 패스워드 인코딩 에러가 일어나지 않고 정상 로그인이 됨.   \n\n      * UserDetalis 객체를 쓸 경우, 코드가 길어지기 때문에, 가독성이 떨어진다. \n      \n      * 스프링 시큐리티 자체에 내장되어 있는 User라는 객체가 UserDetalis를 상속받으므로 User 객체로 대체하면 장황한 코드를 줄일 수 있음.\n\n        * 첫번째 파라미터는 User ID, 두번째는 패스워드, 세번째는 해당 유저의 ROLE이 들어감.\n\n        ```java\n        return new User(account.getEmail(), account.getPassword(), authorities);\n        ```\n\n      * 생성된 ROLE에 의해서 WebSeucrityConfig 클래스에서 접근 권한에 대해 다르게 설정이 가능.\n\n        * `.antMatchers(\"/admin/**\").hasRole(\"ADMIN\")` 와 같이 설정한다면, `/admin` 으로 시작되는 모든 url은 ADMIN ROLE을 가진 유저만 접근이 가능하단 의미가 됨.\n\n\n### prjoect-day-15\n\n  * ToDoList 프로젝트에 Spring Security 적용.\n\n  * 기존의 build.gradle 에 Spring Security 을 위한 의존성 추가.\n\n    ```java\n    compile(\"org.springframework.boot:spring-boot-starter-security\")\n    ```\n  \n  * 프로젝트 하부에 config 패키지를 생성하고 스프링 시큐리티를 설정을 위한 SecurityConfig 클래스 생성.\n\n    * SecurityConfig 클래스에 `@EnableWebSecurity` 어노테이션을 사용하고, WebSecurityConfigurerAdapter 클래스를 상속받는다.\n\n    * 위와 같이 진행할 경우, 사이트 전체가 잠겨서 configure() 메소드를 오버라이딩 해서 페이지의 인증을 해제.\n\n    * 자원에 대한 접근 해제, 모든 경로에 대해 PermitAll.\n\n  * UserRole 도메인을 생성.\n\n    * User와 `@ManyToOne` 어노테이션을 사용해서 관게성을 가진다.\n\n    * User 클래스 쪽에서 UserRole과 `@OneToMany` 관계를 갖고, 엔티티들의 영속관계를 한번에 처리하기 위해, casccade 속성을 주고, UserRole과 User를 둘다 즉시 조회하기 위해서 fetchtype은 EAGER로 설정한다.\n\n    * 관계성을 매핑하고 난 이후, 'entityManagerFactory' 에러가 발생.\n\n      * 기존의 ToDoList와의 관계성 매핑으로 인해서, UserRole과의 관계와 충돌 발생. ToDoList의 FetchType을 Lazy로 주면서 해결.\n    \n    * 도메인 간의 관계성 설정을 마친후, 계정 생성 시도.\n\n      * Spring Security를 적용할 경우, 기존의 Ajax의 POST 호출 시 403 Forbidden 에러가 발생.\n\n      * 원인은 csrf 필터로 인해서, csrf 토큰 값이 누락되어서 발생하는 문제. \n\n      * Ajax 요청 Header에 csrf token 정보를 포함해서 전송.\n\n  * UserDTO 도메인 생성.\n\n    * DTO : 각 계층간의 데이터 교환을 위해 사용되는 순수 객체, DTO는 각 계층간 데이터 전송을 위해 아무런 로직을 갖지 않고 오직 데이터를 담기 위해 사용되는 필드와 Getter/Setter 메서드만 가지는 객체이다.\n\n    * DTO를 사용하는 이유.\n\n      * 어떤 값을 요청할 때, 그 요청한 값을 DTO에 담지 않고 일일이 하나씩 응답해준다면, 네트워크에 엄청나게 많은 트래픽이 발생하기 떄문에 트래픽을 줄이기 위함.\n\n      * @Vaild 어노테이션과 BindingResult 클래스 그리고 DTO 클래스 내에 있는 @NotEmpty, @NotNull, @Email 어노테이션을 통해서 회원가입을 위한 데이터에 유효성 검증을 위해서도 사용하였다.\n\n  * 계정 생성 시에 DB를 조회해서 아이디와 이메일이 중복인지 아닌지 중복 검사 체크.\n\n    * 이상이 없다면, UserRepository에 저장.\n\n  * 계정 생성 성공.\n\n    * 비밀번호가 암호화되서 저장된것을 [확인](./image/24.png)\n\n  * 생성된 계정을 통해서 스프링 시큐리티가 적용된 로그인 로직 구성.\n\n    * 기존의 UserService 클래스에 UserDetailsService 클래스를 상속.\n\n      * loadUserByUsername(String username) 메소드를 오버라이딩.\n\n      * 로그인을 할 때 입력한 username 값을 통해서 DB에서 현재 유저를 찾아온 후, 유저 클래스 생성하여 매핑.\n\n      * 매핑된 유저에 ROLE 필드에 관한 값을 세팅 후, 스프링 시큐리티에서 제공하는 유저 객체에 파라미터로 유저의 아이디, 비밀번호, Roles의 리스트까지 넣고 리턴.\n\n    * SecurityConfig 클래스에서 configureGloba() 메소드에 패스워드 인코딩 처리를 해줌.\n\n    * SecurityConfig 클래스에서 configure() 메소드를 통해서 로그인의 성공 여부에 따른 URL 매핑을 통해 로그인 과정 마무리.\n\n    * 성공적인 로그인을 할 경우, `/list`로 이동되어서 ToDoList의 View를 띄어줌.\n\n    * ToDoList 쪽에 로그아웃 버튼 생성.\n\n      * 로그아웃 버튼을 통해서 로그인 화면으로 이동.\n\n    * 404 에러 페이지와 500 에러 페이지에 따른 뷰 이동.\n\n      * ErroPagerController 클래스 생성 후, 에러 예외 처리 후 에러 뷰 매핑.\n\n    * 스프링 시큐리티를 사용하여 로그인을 했을 때, 현재 사용자 정보를 세션에서 불러오기.\n\n      * 로그인이 성공 한 이후 ToDoList View가 화면 출력 될 떄와 현재 로그인한 유저로 글을 등록 할 때, 현재 유저 정보를 세션에서 가져와야 한다.\n\n      * ToDoListController 클래스에서 /todolist URL에 대해서 GetMapping과 PostMapping을 진행하는 메소드에서 파라미터로 @AuthenticationPrincipal 어노테이션과 함께 스프링 시큐리티에서 제공하는 유저 객체를 추가한다.\n\n      * 그리고 그 유저 객체의 `.getUsername()` 메소드를 통해서 현재 로그인한 유저의 정보를 세션에서 불러올 수 있다.\n\n        ```java\n        @Controller\n        @RequestMapping(\"/todolist\")\n        public class ToDoListController {\n\n          ....\n          ....\n\n          @GetMapping\n          public String list(Model model, @AuthenticationPrincipal org.springframework.security.core.userdetails.User currentUser) {\n              User user = userService.findUserId(currentUser.getUsername());\n              model.addAttribute(\"todoList\", toDoListService.findToDoList(user));\n              return \"todolist/list\";\n          }\n\n          @PostMapping\n          public ResponseEntity\u003c?\u003e postToDoList(@RequestBody @Valid ToDoList toDoList, BindingResult result,\n                                          @AuthenticationPrincipal org.springframework.security.core.userdetails.User currentUser) {\n              if(result.hasErrors()) {\n                  userService.validation(result);\n              }\n\n              User user = userService.findUserId(currentUser.getUsername());\n              toDoListService.PostToDoList(toDoList, user);\n              return new ResponseEntity\u003c\u003e(\"{}\", HttpStatus.CREATED);\n          }\n\n          ....\n          ....\n\n        }\n        ```\n  \n\n### prjoect-day-16\n\n  * 유효성 검증을 위한 코드 일부 수정.\n\n    * UserDTO 클래스에서 컬럼들에 선언해줬던  `@NotEmpty` 어노테이션에서 `@NotBlank` 어노테이션으로 변경.\n\n      * `@NotEmpty` 어노테이션의 경우, null 값과 empty 값은 검증에서 허용하지 않지만, white space 값은 허용하기 떄문에, `@NotBlank` 어노테이션으로 변경.\u003cbr\u003e\u003cbr\u003e\n    \n      |     | `@NotNull` | `@NotEmpty` |`@NotBlank` |\n      :------: | :------------: | :----------: | :-----: |\n      | null  | 허용하지 않음 |허용하지 않음 | 허용하지 않음 |\n      |  \"\" | 허용 | 허용하지 않음 | 허용하지 않음 |\n      | \" \"(space)  | 허용 | 허용 | 허용하지 않음 |\n\n\n  * User 클래스 컬럼 일부 수정.\n\n    * 컬럼으로 들어가는 필드들에 적용되어있는 `@Column` 어노테이션의 속성값을 `@Column(nullable = false)` 으로 변경.\n\n    * User 도메인으로 인해 DB 테이블이 생성될 때, null 이 되어선 안되는 컬럼들에 대해서 Not Null 제약을 걸어주기 위해서 nullable 속성값을 `@Column` 어노테이션에 추가함. \n\n\n### prjoect-day-17\n\n  * 유효성 검증을 위한 코드 일부 추가 및 유효성 검증 부분 마무리.\n\n    * 기존의 DTO 객체단에서 진행하던 검증에 더 해서 프론트 단에서 추가 검증을 진행하기 위해서 프론트 코드 추가.\n\n    * 회원가입 할 때 아이디와 비밀번호 길이에 대한 검증 및 이메일 형식 검증 부분 추가.\n\n    * 로그인을 진행할 때, 아이디 길이와 비밀번호 길이를 프론트 단에서도 검증하는 코드 추가.\n\n    * 로그인 실패시와 로그아웃시에도 그 정보를 출력하는 html 태그 추가.\n\n    * 회원가입시에 Register를 누르기 전에도, 아이디가 중복인지 이메일이 중복인지 뷰를 통해서 나타날 수 있도록 코드 수정.\n\n\n### prjoect-day-18\n\n  * 부분적 테스트 코드 작성 시작.\n\n    * LoginControllerTests 클래스 생성.\n\n      * Ajax 혹은 client의 Request를 테스트 하기 위해서 WebApplicationContext 클래스와 MockMvc 클래스를 사용.\n\n      * root url 접근시의 get 매핑 테스트 코드 작성.\n\n      * 로그인 페이지 접근시의 get 메핑 테스트 코드 작성.\n\n  * 이후에도 여러 테스트 코드를 추가적으로 작성해서 추가할 예정.\n\n\n### prjoect-day-19\n\n  * 소스코드 통합.\n\n  * 계층형 ToDoList 구현하기.\n\n    * 계층형 ToDoList를 위한 Coment 도메인 생성.\n\n      * `idx(키)` -\u003e `Long`\n\n      * `content(내용)` -\u003e `String`\n\n      * `createdDate(생성시간)` -\u003e `LocalDateTime`\n\n      * `modifiedDate(수정시간)` -\u003e `LocalDateTime`\n\n    * Comment 도메인을 생성함으로써 CommentRepository, CommentController, CommentService 클래스 생성.\n\n  * Comment 등록을 위한 View [생성](./image/25.png)\n\n  * View에서 데이터 값을 전송하기 위한, CommentDTO 클래스 생성.\n\n  * 댓글 등록 및 데이터 베이스 값 저장.\n\n    * Comment 도메인과 ToDoList 도메인의 관계성 매핑.\n\n      * Comment 도메인에서 `@ManyToOne` 관계 매핑.\n\n      * ToDoList 도메인에서 `@OneToMany` 관계 매핑.\n\n    * CommentController 클래스에서 댓글 등록을 위한 Post 요청 메소드 생성.\n\n      * Post 요청 메소드 내에서 등록을 위한 비지니스 로직을 처리하기 위해 서비스 호출.\n\n      * 댓글 등록할 때, 댓글의 데이터에 대한 유효성 검증을 위한, 서비스 호출. (`validation()`)\n\n      * 검증이 끝났다면, `@Builder` 어노테이이션을 이용한 빌더 패턴을 이용해서 Comment 객체 생성 후, ToDoList의 add 메소드 실행.\n\n      * 마지막으로 CommentRepository 에 필요한 로직을 처리한 Comment 객체 저장.\n\n      * 댓글 등록 View에서 AJAX 호출을 통해서 Post 메소드 호출을 한 뒤, DB에 Comment 값 [저장완료](./image/26.png)\n\n\n### prjoect-day-20\n\n  * 사용하지 않은 css, js 파일 모두 삭제.\n\n  * 중복되는 코드 부분들은 하나로 통일.\n\n  * 깔끔한 뷰를 위해서 html 및 css 그리고 js 코드 부분 수정.\n\n  * 댓글을 입력하면 입력한 View가 DB 값에 저장 이후, To Do List에 출력되도록 설정.\n\n  * 댓글 수정 및 삭제 구현.\n\n    * 댓글 수정 및 삭제를 위한 비지니스 로직 추가 및 put 매핑과 delete 매핑 추가.\n\n    * 댓글 수정 및 삭제를 하기 위해 View에서 AJAX 호출을 통해서 put 또는 delete 메소드 호출을 한 뒤, DB에 Comment 수정 또는 삭제 적용.\n\n  * 계층형 ToDo로 작성된 댓글에 대해서도 완료 여부에 대한 설정 가능.\n\n    * Comment 도메인에 Status 컬럼 추가 및 체크 박스 여부에 따라 Status 값이 False 또는 True로 변경.\n\n\n### prjoect-day-21\n\n  * 계층형 ToDoList 완료 여부 설정 및 컬럼 추가.\n\n  * 계층형 ToDoList 삽입, 삭제, 수정, 완료시에 페이지가 Reload가 되어서 접히는 이슈 해결.\n\n    * 데이터를 CommentDTO 객체를 이용해서 서버에 보낸 뒤, 다시 CommentDTO를 반환받아서 그 객체를 토대로 자바스크립트 객체 생성.\n\n    * 자바스크립트로 생성한 Comment 객체를 이용해서 페이지를 리로드 하지 않고, 삽입, 수정, 삭제 한 로직에 따른, 뷰를 반영. \n\n\n### prjoect-day-22\n\n  * ToDoList 수정 진행시에, 수정 버튼 디자인 변경 및 다른 삭제, 코맨트, 체크박스 등의 버튼들을 비활성화 처리.\n\n  * 계층형 ToDoList 수정시에도, 수정 버튼 디자인 변경 및 다른 삭제 및 체크박스 버튼 들을 비활성화 처리.\n\n  * 일부 HTML의 CSS 속성 및 View 변경.\n\n\n### prjoect-day-23\n\n  * 개선사항 및 모든 문제들은 [issue](https://github.com/dongh9508/Project-ToDoList/issues)로 등록해서 관리.\n\n  * 등록된 이슈들을 토대로 이슈들을 처리하기 위한 Branch 생성 후, 문제가 없을 경우, Master Branch로 Merge 하는 방식으로 프로젝트를 진행할 예정임.\n\n  * UserDTO 클래스의 유효성 검증 어노테이션인 `@Pattern` 어노테이션 추가.\n\n    * 테스트 코드를 원할하게 동작하기 위해서, 기존의 js가 처리해주던 프론트에서의 검증 뿐만 아니라, 백앤드에서도 아이디 및 비밀번호를 검증해주기 위해 추가. \n\n  * [#1](https://github.com/dongh9508/Project-ToDoList/issues/1) 이슈 처리 및 개선사항 Master Branch로 합병.\n\n    *  [#1](https://github.com/dongh9508/Project-ToDoList/issues/1) 이슈인 회원가입 테스트 코드 작성 완료.\n\n### prjoect-day-24\n\n  * [#3](https://github.com/dongh9508/Project-ToDoList/issues/3) 이슈 처리 및 개선사항 Master Branch로 합병.\n\n    * [#3](https://github.com/dongh9508/Project-ToDoList/issues/3) 이슈인 로그인 테스트 코드 작성 완료.\n\n    * 로그인 테스트 코드 작성 중에 MockMvc를 이용한 쿠키 상태 값을 불러오는 것이 안되어서 쿠키 값 갱신 테스트는 완료하지 못하였음.\n\n### prjoect-day-25\n\n  * [#5](https://github.com/dongh9508/Project-ToDoList/issues/5) 이슈 처리 및 개선사항 Master Branch로 합병.\n\n    * [#5](https://github.com/dongh9508/Project-ToDoList/issues/5) 이슈인 ToDoList 테스트 코드 작성 완료.\n\n      * ToDoList Get 요청\n\n        * `/`, `/todolist` 요청.\n\n      * ToDo 등록\n\n        * ToDo 문자열 길이 0\n\n          * ToDo의 최소 길이 미달로 등록 실패.\n\n        * ToDo 문자열 길이 256\n\n          * ToDO의 최대 길이 초과로 등록 실패.\n\n        * ToDo 문자열 길이 1 ~ 255 \n\n          * ToDo의 유효한 문자열 길이 범위이므로 등록 성공.\n\n        * 정상 등록된 ToDoList 객체 비교.\n\n          * 등록된 ToDoList, ToDoList.CreatedDate - `NotNull`\n\n          * ToDoList.CompletedDate - `Null`\n\n          * 현재 로그인한 User.Idx와 ToDoList를 등록한 User의 Idx 일치.\n\n      * ToDo 완료.\n\n        * ToDo 생성.\n\n          * 생성 직후, ToDo의 Status는 `false`, ToDo의 CompletedDate도 `Null`\n\n        * 생성된 ToDo 완료 처리, `put(\"/todolist/status/{idx}\")` 요청.\n\n          * ToDo의 Status는 `true`, ToDo의 CompletedDate는 `LocalDateTime.now()`\n\n      * ToDo 삭제.\n\n        * ToDo 생성.\n\n          * 생성된 ToDo 객체는 `NotNull`\n\n        * ToDo 삭제 요청, `delete(\"/todolist/{idx}\")` 요청.\n\n          * ToDo 삭제 확인(`Null`)\n\n      * ToDo 수정\n\n        * ToDo 생성\n\n          * ToDo 등록 내용 확인.\n\n        * ToDo 수정 요청, `put(\"/todolist/{idx}\")` 요청.\n\n          * 변경된 description 저장.\n\n          * DB에서 변경된 description 확인. \n\n### prjoect-day-26\n\n  * [#8](https://github.com/dongh9508/Project-ToDoList/issues/8) 이슈 처리 및 개선사항 Master Branch로 합병.\n\n    * [#8](https://github.com/dongh9508/Project-ToDoList/issues/8) 이슈인 로그인 테스트 코드 작성 완료.\n\n    * Comment 등록.\n\n      * 등록 요청 성공 및 DB 내 등록 여부 확인 .\n\n      * 내용 등록 시 길이(빈 문자열, 최대 글자 초과) 검사.\n\n      * ToDo 와의 관계성 확인(ToDoListIdx에 대한 List의 갯수).\n\n    * Comment 완료.\n\n      * 완료 요청 성공 및 DB 내 상태 변경 및 완료 날짜 확인.\n\n    *  Comment 수정\n\n        * 내용 등록 길이(빈 문자열, 최대 글자 초과) 검사.\n\n        * 수정 요청 성공 및 DB 안의 수정 내용 및 수정 날짜 확인.\n\n    * Comment 삭제\n\n      * 삭제 요청 성공 및 DB 내 삭제 여부 확인.\n\n### prjoect-day-27\n\n  * [#10](https://github.com/dongh9508/Project-ToDoList/issues/10) 이슈 처리 및 개선사항 Master Branch로 합병.\n\n    * [#10](https://github.com/dongh9508/Project-ToDoList/issues/10) 이슈인 아이디, 비밀번호 찾기 기능 추가.\n\n    * 로그인 페이지 뷰 일부 변경\n\n    * `login.js` 생성 후, 로그인 페이지에서 처리되던 모든 자바스크립트 로직을 `login.js` 파일로 옮김.\n\n    * 아이디 찾기.\n\n      * 계정 생성 시 등록했던 이메일을 통해서 아이디 찾기.\n\n        * 이메일이 존재하면 아이디를 이메일로 전송.\n\n        * 이메일이 존재하지 않는다면 아이디 찾기 실패.\n\n    * 비밀번호 찾기.\n\n      * 계정 생성 시 등록했던 아이디와 이메일을 통해서 비밀번호 찾기.\n\n        * 아이디와 이메일이 존재하고 일치하면, 이메일에 인증번호를 전송 후, 일치하면, 비밀번호를 새롭게 설정.\n\n        * 아이디와 이메일이 둘 중 하나라도 존재하지 않거나, 아이디와 이메일이 일치 하지 않을시 비밀번호 찾기 실패.\n\n### prjoect-day-28\n\n  * [#12](https://github.com/dongh9508/Project-ToDoList/issues/12) 이슈 처리 및 개선사항 Master Branch로 합병.\n\n    * [#12](https://github.com/dongh9508/Project-ToDoList/issues/12) 이슈인 비밀번호 찾는 로직 개선 및 수정.\n\n  * 비밀번호 찾는 로직 변경으로 인한 코드 일부 수정.\n\n    * 인증번호를 인증하기 위해 Map 자료구조를 사용하였으나, 이 부분보다 더 나은 방법으로 해결하기 위해 로직 변경.\n\n    * 비밀번호 데이터를 올바르게 전송하기 위한, FindPasswordDTO 객체를 생성.\n\n    * LoginService 클래스를 빈으로 등록할 때, 스코프를 싱글톤으로 주지 않고, 세션으로 주어서 접속한 세션마다 빈이 생성되도록 로직 변경.\n\n      * 이렇게 변경 후, 접속한 세션에 따라서 LoginService 빈이 새롭게 주입되고, 각 세션은 각기 다른 하나의 LoginService 빈들을 주입 받는다. 즉, 접속한 유저마다 다른 LoginService 빈들을 주입받고, 그 LoginService 빈들을 이용해서 비밀번호 및 아이디를 찾는 로직을 수행한다. \n\n      * 그렇기 떄문에, 다른 유저들과 LoginService 빈을 공용으로 사용할 일이 없기 때문에, 인증 로직이 각 유져별로(세션별로) 완전히 독립적으로 수행된다.\n\n      * 또 세션이 종료되면(브라우저가 종료되는 등) 해당 세션의 LoginService 빈도 소멸하기 떄문에, 그 안에서 처리되던 인증 번호 및 인증 로직도 전부 소멸한다.\n\n        * 인증번호를 받고, 브라우저를 종료 후, 다시 접속해서 이전에 받은 인증번호를 이용하려 하면 인증이 되지 않는다.\n\n### 이 이후부터는 [Issues](https://github.com/dongh9508/Project-ToDoList/issues)에서 업데이트 사항들을 확인할 수 있습니다.\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdonghl-dev%2Fproject-todolist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdonghl-dev%2Fproject-todolist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdonghl-dev%2Fproject-todolist/lists"}