1. StudentDTO
package model;
// VO, DTO - 웹 (자료형 역할을 한다고 해서)
public class StudentDTO {
private int num; // pk
private String name;
private int score;
public StudentDTO(int num, String name, int score) {
this.num = num;
this.name = name;
this.score = score;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [num=" + num + ", name=" + name + ", score=" + score + "]";
}
}
DTO는 말 그대로 자료형을 정의하는 역할. 클래스에서 멤버변수 정의해서 생성자 만들고 getter/setter 만들던걸 Model의 DTO에서 그대로 한다고 생각하면 된다.
멤버변수에 함부로 접근할 수 없도록 전부 private로 선언해준 후, 매개변수를 가지는 생성자를 하나 만들어주었다.
객체가 하나 생성될 때마다 그 객체는 이름, 점수, 번호가 함께 저장되어야 한다.
참고로 생성자를 public으로 선언해주어야 다른 곳에서 가져다 쓸 수가 있다.
참고로, 학번 같은 경우는 하나씩 차례대로 늘어나도록 했는데 여기에서는 컨트롤러에서 ++을 해주도록 설정해주었기에 model dto에서는 별 다른 작성을 하지 않았다.
그리고 내가 생각하기에도 C에서 증가시키도록 하는게 더 간편한 방법 같다... 물론 내가 잘 할 줄 몰라서 그런거겠지만?
private로 멤버변수들을 선언했으니 내부의 데이터에 안전한 방법으로 접근하여 값을 읽거나 변경할 수 있도록 (캡슐화) getter/setter도 만들어준다.
또, toString() 오버라이딩을 통해 객체의 데이터 정보 자세히 볼 수 있도록 했다.
dto의 역할은 이게 전부다. 자료형 정의, 데이터 전달, 생성자 생성, getter/setter, toString() 오버라이딩.
"안전한 데이터 전달을 위한 객체"
2. StudentDAO
package model;
import java.util.ArrayList;
// DAO(DTO와 한쌍)
// CRUD 메서드만 가진다.
// 다른 곳에서 사용할 수 있어야 해서 public 사용
//DAO는 5개의 메서드만 가질 수 있다!!!
public class StudentDAO {
// DB의 역할
private ArrayList<StudentDTO> datas;
// 아무에게나 오픈하면 안되므로 private로 선언
public StudentDAO() { // 다른 곳에서 생성자 사용할 수 있게 PUBLIC
this.datas = new ArrayList<>();
// 샘플 데이터 추가
this.datas.add(new StudentDTO(1001, "티모", 98));
this.datas.add(new StudentDTO(1002, "모르가나", 64));
this.datas.add(new StudentDTO(1003, "오리아나", 40));
}
// C에서 전체출력하겠다. 라고 하면
// 내가 가지고 있던 DB의 내용을 모두
// C로 전달해야 함
public ArrayList<StudentDTO> selectAll() {
// 내가 가지고 있던 DB의 내용을 모두
ArrayList<StudentDTO> datas = new ArrayList<>();
for(int i=0;i<this.datas.size();i++) {
int num=this.datas.get(i).getNum();
String name=this.datas.get(i).getName();
int score=this.datas.get(i).getScore();
datas.add(new StudentDTO(num,name,score));
} // 리스트 안의 모든 내용을 전달함
// 가지고 있는 데이터를 한번 복사해서 준다.
// selectAll 할때마다 리스트를 매번 새로 만든다. 복사체를 만든다??
return datas;
}
//public Object selectOne() {
// return null;
//}
public StudentDTO selectOne(int num) {
StudentDTO data=null;
for(int i=0;i<this.datas.size();i++) {
if(num == this.datas.get(i).getNum()) {
String name=this.datas.get(i).getName();
int score=this.datas.get(i).getScore();
data=new StudentDTO(num,name,score);
}
}
return data;
}
public ArrayList<StudentDTO> selectAll(String searchKeyword) { // searchContent
ArrayList<StudentDTO> datas=new ArrayList<>();
for(int i=0;i<this.datas.size();i++) {
if(this.datas.get(i).getName().contains(searchKeyword)) {
int num=this.datas.get(i).getNum();
String name=this.datas.get(i).getName();
int score=this.datas.get(i).getScore();
datas.add(new StudentDTO(num,name,score));
}
}
return datas;
}
public boolean insert(String name,int score,int num) {
this.datas.add(new StudentDTO(num,name,score));
return true;
}
public boolean update(int num,String name) {
for(int i=0;i<this.datas.size();i++) {
if(num == this.datas.get(i).getNum()) {
this.datas.get(i).setName(name);
return true;
}
}
return false;
}
public boolean delete(int num) {
for(int i=0;i<this.datas.size();i++) {
if(num == this.datas.get(i).getNum()) {
this.datas.remove(i);
return true;
}
}
return false;
}
}
□ DAO는 DTO와 한쌍이다.
□ 5가지의 CRUD 메서드만 가진다는 특징이 있다. (selectOne, selectAll, insert, update, delete)
□ 다른 곳에서 이용할 수 있어야 하므로 DAO는 public으로 선언한다.
private ArrayList<StudentDTO> datas;
// 아무에게나 오픈하면 안되므로 private로 선언
public StudentDAO() { // 다른 곳에서 생성자 사용할 수 있게 PUBLIC
this.datas = new ArrayList<>();
// 샘플 데이터 추가
this.datas.add(new StudentDTO(1001, "티모", 98));
this.datas.add(new StudentDTO(1002, "모르가나", 64));
this.datas.add(new StudentDTO(1003, "오리아나", 40));
}
다음 코드에서는 StudentDTO를 자료형으로 하는 ArrayList인 datas를 선언하고 있다. 외부에서 함부로 접근 할 수 없도록 private로 선언했다.
StudentDAO가 생성될 때 자동 실행될 생성자를 하나 만들어주는데, 그 안에서는 위에서 선언만 한 datas를 초기화해준다. (선언만 됐을 땐 null 상태)
이는 datas를 null인 상태로 놔두면 StudentDAO가 호출될 때마다 NullPointerException이 발생하기 때문인데, 위에서 private ArrayList<StudentDTO> datas;를 한 것은 선언만 된 것이지, 메모리에 할당된 상태가 아니기 때문에 add() 같은 함수를 사용했을 때 datas라고 가리킬 공간이 존재하지 않는다. (add()를 사용할 공간 자체가 존재하지 않음)
그렇기 때문에 생성자 안에서 StudentDAO가 호출될 때마다 datas를 초기화하여 ArrayList를 담을 공간을 생성하고, 생성자 안에서 샘플 데이터마저 생성해줌으로써 StudentDAO를 호출할 때마다 ArrayList라는 datas의 공간이 할당되고, 그 안에는 샘플 데이터가 이미 존재하도록 세팅하는 것이다.
보면서 생긴 헷갈리는 점 / 궁금증들.
+1) 왜 굳이 초기화를 생성자 안에서 할까? 생성자 밖에서 선언 / 초기화를 한번에 진행하면 안되는 걸까?
private ArrayList<StudentDTO> datas = new ArrayList<>();
왜 이처럼 생성자밖에서 한번에 선언/초기화를 하지 않는 건지 너무 궁금해서 찾아봤다.
우선 위에서는 StudentDAO의 datas 안에 StudentDTO 객체를 3개 생성한 것이다.
그러면 StudentDAO의 리스트 하나에 StudentDTO 객체가 3개 담겨있는 것이다.
그런데, 이 DAO는 뷰에서도 객체를 생성해서 쓰이고, 컨트롤러에서도 객체 생성해서 쓰이게 되는데 만약 위처럼 생성자 위에서 한 줄로 초기화되면 뷰에서도, 컨트롤러에서도 동일한 리스트 하나를 공유하게 되는 것이다.
그렇게 되면, 뷰나 컨트롤러 중 한쪽에서 데이터를 변경하면, 다른 곳에서도 데이터가 바뀌는 문제가 생길 수 있다.
즉, DAO 객체를 생성하는 곳마다 각각 독립적으로 DAO를 사용하기 위해서 생성자 안에서 초기화를 하는 것이다.
(객체 생성하면서 각자 생성자를 호출하게 되는데 생성자 안에서 초기화하면 뷰에서 DAO 객체 생성할 때 새로운 리스트 하나, 컨트롤러에서 DAO 객체 생성할 때 하나. 이렇게 각각 리스트를 갖게 되는 것이다.)
+ 2) 객체 생성과 초기화의 차이
this.datas = new ArrayList<>();
이 코드는 new ArrayList<>();를 통해 datas를 초기화하는 것이다.
생성자 밖에 이미 ArrayList<StudentDTO> datas가 선언되어 있기는 하지만 아직 null 상태라서 사용할 수 없는 상태이다.
그래서 new ArrayList<>();를 통해 datas에 비어있는 리스트를 할당해주는 것이다.
그러면 비어있는 리스트 공간을 할당해줌으로써 datas는 사용할 수 있는 상태가 된다!
즉, 리스트를 사용할 수 있도록 하기 위해 비어있는 리스트 공간을 만들어주는 것!
this.datas.add(new StudentDTO(1001, "티모", 98));
이 코드는 객체를 생성하는 코드이다. new StudentDTO(매개변수 1, 2, 3)라는 생성자를 불러와서 객체를 생성하고 있다.
이건 메모리에 새로운 StudentDTO 객체가 만들어지는 것이고, 생성자가 호출된다는 특징이 있다.
새로운 인스턴스를 메모리에 생성하는 것. 즉, 티모라는 새로운 객체를 만들어서 리스트에 집어넣는 것이다.
초기화 | this.datas = new ArrayList<>(); | 이미 존재하는 필드를 사용하기 위한 준비. 새로운 인스턴스를 메모리에 할당하는 것이 아니다. |
객체 생성 | this.datas.add(new StudentDTO(1001, "티모", 98)); | 아직 존재하지 않는 객체를 생성함으로써 새로운 인스턴스를 메모리에 할당 |
① selectAll()
public ArrayList<StudentDTO> selectAll() {
// 내가 가지고 있던 DB의 내용을 모두
ArrayList<StudentDTO> datas = new ArrayList<>();
for(int i=0;i<this.datas.size();i++) {
int num=this.datas.get(i).getNum();
String name=this.datas.get(i).getName();
int score=this.datas.get(i).getScore();
datas.add(new StudentDTO(num,name,score));
} // 리스트 안의 모든 내용을 전달함
// 가지고 있는 데이터를 한번 복사해서 준다.
// selectAll 할때마다 리스트를 매번 새로 만든다. 복사체를 만든다??
return datas;
}
selectAll()은 모든 정보를 출력해주는 역할이다. 그러므로 StudentDTO를 자료형으로 하는 ArrayList를 하나 생성해준다.
이름은 datas로, 기존 데이터를 복사해서 보내주는 역할을 한다.
왜냐하면 기존 데이터에 변경 사항이 생기면 안되니까! (원본 데이터 보호)
그러므로 복사해둘 공간인 datas를 생성하는 것이다.
for문을 통해서 datas의 크기만큼 반복하면서 기존 StudentDAO 리스트에 있는 번호, 이름, 점수를 모두 가져와서 datas에 추가한다.
* 여기서 this.datas는 StudentDAO의 리스트를 말한다!
즉, datas -> 복사본 / this.datas -> 원본
datas에는 StudentDAO 리스트에 있는 모든 정보가 복사되게 되고, selectAll은 이 datas를 반환해준다.
즉, selectAll을 호출할 때마다 새로운 리스트 datas를 생성하여 기존 리스트(this.datas)에 있는 모든 정보를 복사해 보내주게 된다.
public ArrayList<StudentDTO> selectAll(String searchKeyword) { // searchContent
ArrayList<StudentDTO> datas=new ArrayList<>();
for(int i=0;i<this.datas.size();i++) {
if(this.datas.get(i).getName().contains(searchKeyword)) {
int num=this.datas.get(i).getNum();
String name=this.datas.get(i).getName();
int score=this.datas.get(i).getScore();
datas.add(new StudentDTO(num,name,score));
}
}
return datas;
}
이것도 selectAll(). 같은 selectAll()이라도 매개변수가 다르면 하나의 DAO 안에 여러 개의 selectAll()이 존재할 수 있다.
===>> 메서드 오버로딩!
이 코드는 만약 학생부에 고구마, 감자, 고등어가 있을 때 '고'를 입력하면 '고'가 포함된 고구마, 고등어의 정보를 모두 반환하는 메서드이다.
② selectOne()
public StudentDTO selectOne(int num) {
StudentDTO data=null;
for(int i=0;i<this.datas.size();i++) {
if(num == this.datas.get(i).getNum()) {
String name=this.datas.get(i).getName();
int score=this.datas.get(i).getScore();
data=new StudentDTO(num,name,score);
}
}
return data;
}
selectOne은 하나의 데이터만 반환해주는 메서드이다.
먼저, 반환할 객체를 저장할 StudentDTO를 자료형으로 하는 data 변수를 하나 선언해준 후
for문을 통해 기존 데이터(this.datas)를 돌면서 입력된 번호와 동일한 번호가 있다면 기존 데이터(this.datas)에서 특정 num의 이름, 점수를 가져와서 data라는 새로운 객체를 생성한다.
* 하나의 데이터만 가져오므로 변수명은 datas가 아닌 data
그리고 기존 데이터(this.datas)를 복사한 새로운 객체인 data를 반환해주게 되는데, 이때, 함수의 scope 이슈로 인해, StudentDTO를 자료형으로 하는 data를 위에서 null로 초기화 해준다.
③ insert()
public boolean insert(String name,int score,int num) {
this.datas.add(new StudentDTO(num,name,score));
return true;
}
insert는 데이터를 삽입하는 메서드이다.
이름, 점수, 번호를 매개변수로 받아와 StudentDTO 타입의 객체를 하나 생성하고 StudentDAO 리스트에 저장하게 된다.
데이터 성공 삽입 시 true를 반환한다.
④ update()
public boolean update(int num,String name) {
for(int i=0;i<this.datas.size();i++) {
if(num == this.datas.get(i).getNum()) {
this.datas.get(i).setName(name);
return true;
}
}
return false;
}
update는 데이터를 변경하는 메서드이다.
이름과 번호를 받아와서, this.datas만큼 돌면서 만약 해당하는 번호가 있다면 그 번호의 이름을 입력받은 이름으로 바꾼다.
변경 성공 시 true, 실패 시 false를 반환한다.
⑤ delete()
public boolean delete(int num) {
for(int i=0;i<this.datas.size();i++) {
if(num == this.datas.get(i).getNum()) {
this.datas.remove(i);
return true;
}
}
return false;
}
}
delete는 데이터를 삭제하는 메서드이다.
this.datas만큼 돌면서 만약 this.datas에 받아온 번호가 존재한다면 그 번호의 데이터를 삭제한다.
삭제제 성공 시 true, 실패 시 false를 반환한다.
코드 직접 다시 작성해보면서 익숙해지도록 하자.
'IT > JAVA' 카테고리의 다른 글
웹 크롤링 (0) | 2025.02.10 |
---|---|
MVC 패턴 복습 2 (0) | 2025.02.09 |
MVC 패턴 - Controller 분석 (0) | 2025.02.07 |
MVC 패턴 복습 (0) | 2025.02.07 |
파일 입출력 (0) | 2025.02.04 |