CLI 프레임워크를 사용하여 TODO APP만들기~!
settings.gradle
rootProject.name = 'ScoulaTodo'
include ':ScoulaCli'
project(':ScoulaCli').projectDir=new File('C:\\KB_ITs_Your_Life\\Scoula\\ScoulaLib\\scoulacli')
build.gradle
dependencies {
implementation project(':ScoulaCli')
implementation 'com.mysql:mysql-connector-j:8.3.0'
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
testCompileOnly 'org.projectlombok:lombok:1.18.30'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.30'
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
Annotation Processing 활성화

IntelliJ DataSource 등록

프로젝트 루트에 todo.sql 파일 추가

// UserVO.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder // 기존 코드에서 Builder만 추가
public class UserVO {
private String id;
private String password;
private String name;
private String role;
}
- 회원가입
- 로그인
- 로그아웃
- 종료
createMenu() 대신 다른 방식으로 메뉴 운영void setMenu(Menu menu) 메서드 추가// App.java
public abstract class App {
Menu menu;
public App() {
}
// 메서드 추가 - 외부에서 메뉴가 들어오도록~
public void setMenu(Menu menu) {
this.menu = menu;
}
...


TodoApp.java
public class TodoApp extends App {
Menu userMenu; // 로그인 상태
Menu anonymousMenu; // 로그아웃 상태
@Override
public void init() {
anonymousMenu = new Menu();
anonymousMenu.add(new MenuItem("로그인", this::login));
anonymousMenu.add(new MenuItem("가입", this::join)); // 아직 구현x
anonymousMenu.add(new MenuItem("종료", this::exit));
userMenu = new Menu();
userMenu.add(new MenuItem("로그아웃", this::logout));
userMenu.add(new MenuItem("종료", this::exit));
setMenu(anonymousMenu); // 시작은 annonymousMenu로
}
public void join() {
}
public void login() {
setMenu(userMenu);
}
public void logout() {
if(Input.confirm("로그아웃 할까요?")) {
setMenu(anonymousMenu); // 메뉴 교체
}
}
// exit 메소드 추가 - 교안에 없음
public void exit() {
System.exit(0); // 프로그램 종료
}
public static void main(String[] args) {
final TodoApp app = new TodoApp();
app.run();
}
}

UsernameDuplicationException.java
package org.scoula.todo.exception;
// 회원가입 -사용자 ID 중복
public class UsernameDuplicationException extends Exception{
public UsernameDuplicationException() {
super("이미 사용중인 사용자 ID 입니다");
}
}
PasswordMissmatchException.java
package org.scoula.todo.exception;
// 회원가입 - 비밀번호, 비밀번호2 불일치
public class PasswordMissmatchException extends Exception{
public PasswordMissmatchException() {
super("비밀번호가 맞지 않습니다");
}
}
AccountService.java
package org.scoula.todo.service;
// 회원가입
public class AccountService {
UserDao dao = new UserDaoImpl();
public void join() {
try {
UserVO user = getUser();
dao.create(user); // 유저 정보 받으면 dao를 이용해 create~
} catch (UsernameDuplicationException | PasswordMissmatchException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
throw new RuntimeException(e); //
}
}
public boolean checkDuplication(String username) throws UsernameDuplicationException, SQLException {
Optional<UserVO> result = dao.get(username); // username이 있으면 리턴, 없으면 Null
if (result.isPresent()) { // 데이터가 있으면 ID 중복
throw new UsernameDuplicationException();
}
return false;
}
public UserVO getUser() throws SQLException, UsernameDuplicationException, PasswordMissmatchException {
String username = Input.getLine("사용자 ID: ");
checkDuplication(username); // 중복 체크
String password = Input.getLine("비밀번호: ");
String password2 = Input.getLine("비밀번호 확인: ");
if (!password.equals(password2)) {
throw new PasswordMissmatchException();
}
String name = Input.getLine("이름: ");
String role = Input.getLine("역할: ");
return UserVO.builder()
.id(username)
.password(password)
.name(name)
.role(role)
.build();
}
}
TodoApp.java
public class TodoApp extends App {
Menu userMenu; // 로그인 상태
Menu anonymousMenu; // 로그아웃 상태
AccountService accountService = new AccountService();
@Override
public void init() {
anonymousMenu = new Menu();
anonymousMenu.add(new MenuItem("로그인", this::login));
anonymousMenu.add(new MenuItem("가입", accountService::join));
anonymousMenu.add(new MenuItem("종료", this::exit));
userMenu = new Menu();
userMenu.add(new MenuItem("로그아웃", this::logout));
userMenu.add(new MenuItem("종료", this::exit));
setMenu(anonymousMenu); // 시작은 annonymousMenu로
}
public void join() {
}
public void login() {
setMenu(userMenu);
}
public void logout() {
if(Input.confirm("로그아웃 할까요?")) {
setMenu(anonymousMenu); // 메뉴 교체
}
}
// exit 메소드 추가 - 교안에 없음
public void exit() {
System.exit(0); // 프로그램 종료
}
public static void main(String[] args) {
final TodoApp app = new TodoApp();
app.run();
}
}
UserVo user; //로그인 사용자Context.java
package org.scoula.todo.context;
@Getter
@Setter
public class Context {
private UserVO user; // 로그인 사용자 정보, null이면 로그아웃 상태
// 싱글톤 패턴
private Context() {}
private static Context context = new Context();
public static Context getContext() {
return context;
}
}
LoginFailException.java
package org.scoula.todo.exception;
public class LoginFailException extends Exception{
public LoginFailException() {
super("사용자 ID 또는 비밀번호가 일치하지 않습니다");
}
}
LoginService.java
package org.scoula.todo.service;
import java.sql.SQLException;
public class LoginService {
UserDao dao = new UserDaoImpl();
public void login() throws SQLException, LoginFailException {
String username = Input.getLine("사용자 ID: ");
String password = Input.getLine("비밀번호: ");
UserVO user = dao.get(username).orElseThrow(LoginFailException::new); // 일치하는 id가 아니면 예외 발생
if (user.getPassword().equals(password)) {
Context ctx = Context.getContext();
ctx.setUser(user);
} else {
throw new LoginFailException();
}
}
}
TodoApp.java
public class TodoApp extends App {
Menu userMenu; // 로그인 상태
Menu anonymousMenu; // 로그아웃 상태
AccountService accountService = new AccountService();
LoginService loginService = new LoginService();
@Override
public void init() {
anonymousMenu = new Menu();
anonymousMenu.add(new MenuItem("로그인", this::login));
anonymousMenu.add(new MenuItem("가입", accountService::join));
anonymousMenu.add(new MenuItem("종료", this::exit));
userMenu = new Menu();
userMenu.add(new MenuItem("로그아웃", this::logout));
userMenu.add(new MenuItem("종료", this::exit));
setMenu(anonymousMenu); // 시작은 annonymousMenu로
}
public void join() {
}
public void login() {
try {
loginService.login();
setMenu(userMenu);
} catch (SQLException e){
throw new RuntimeException(e);
} catch (LoginFailException e){
System.out.println(e.getMessage());
}
}
public void logout() {
if(Input.confirm("로그아웃 할까요?")) {
setMenu(anonymousMenu); // 메뉴 교체
}
}
// exit 메소드 추가 - 교안에 없음
public void exit() {
System.exit(0); // 프로그램 종료
}
public static void main(String[] args) {
final TodoApp app = new TodoApp();
app.run();
}
}
TodoApp.java
public void logout() {
if(Input.confirm("로그아웃 할까요?")) {
Context.getContext().setUser(null);
setMenu(anonymousMenu); // 메뉴 교체
}
}
[0717]
todo.sql
DROP TABLE IF EXISTS TODO;
CREATE TABLE TODO (
ID INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY,
TITLE VARCHAR(128) NOT NULL,
DESCRIPTION VARCHAR(512) NULL,
DONE BOOLEAN,
USERID VARCHAR(12) NOT NULL,
FOREIGN KEY (USERID) REFERENCES USERS(ID)
ON UPDATE CASCADE
ON DELETE CASCADE
);
INSERT INTO TODO(TITLE, DESCRIPTION, DONE, USERID)
VALUES ('야구장', '프로야구 경기 보기', FALSE, 'GUEST'),
('놀기', '열심히 놀기', FALSE, 'GUEST'),
('DB공부', 'JDBC 모듈평가 공부', FALSE, 'MEMBER'),
('코테', '알고리즘 공부', TRUE, 'GUEST');
