Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- SpringBoot
- 유효성검사
- 서비스레이어
- 비즈니스레이어
- @ResponseBody
- @
- frontController
- produces
- PointCut
- application.properties
- spring
- Java
- springjdbc
- 스프링
- 생성자주입
- @RequestMapping
- @Valid
- c:if
- jointpoint
- after-throwing
- springmvc
- 바인딩변수
- @RequestParam
- Model
- gradle
- MVC
- 어노테이션
- AOP
- .xml
- 의존주입
Archives
- Today
- Total
메모장
[실습문제] 자판기프로그램 MVC패턴 본문
728x90
반응형
실습문제 !
새로운 프로그램 작성하기 == 자판기 프로그램
-> 음료수 클래스
PK,이름,가격,재고
음료추가(),음료목록출력(),구매(),음료삭제()
C, R, U, D 기능 넣어서
MVC 패턴으로 작성하기
+ 음료 검색
+ 장바구니 추가 !
Model - DrinkVO
package model;
public class DrinkVO {
private int num;
private String name;
private int price;
private int cnt;
public DrinkVO(int num,String name,int price,int cnt) {
this.num=num;
this.name=name;
this.price=price;
this.cnt=cnt;
}
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 getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getCnt() {
return cnt;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
@Override
public String toString() {
String msg=num+"번 "+name+" "+price+"원 ";
if(this.cnt==0) {
msg+="[X]";
}
else {
msg+="["+cnt+"개]";
}
return msg;
}
@Override
public boolean equals(Object obj) { // 오버라이딩
DrinkVO drinkVO = (DrinkVO)obj; // 다운 캐스팅
if(this.num==drinkVO.num) {//만약 내 PK 와 비교대상의 PK가 같아?
return true; // 같으면 참이야
}
return false;
}
}
Model - DrinkDAO
package model;
import java.util.ArrayList;
// DAO의 CRUD(비즈니스 메서드,핵심 로직)는
// 어떤 추가 요청사항에도 절대!
// "메서드 시그니처"가 변하지않도록 코드를 작성해야함!!!!!
// "메서드 시그니처"가 변경되면 다른 파트에 영향을 준다...
// '기능' 변경은 괜찮다.
// 결론) "메서드 시그니처"는 설계단계에서 절대로 변경되면 안됨!!!!!!!!!!
public class DrinkDAO {
private static int PK = 1001;
private ArrayList<DrinkVO> datas;
public DrinkDAO() {
datas = new ArrayList<DrinkVO>();
datas.add(new DrinkVO(PK++, "콜라", 1200, 3));
datas.add(new DrinkVO(PK++, "사이다", 900, 2));
datas.add(new DrinkVO(PK++, "환타", 1500, 1));
}
// C
public boolean insert(DrinkVO vo) { // DrinkVO vo로 인자 통일
// 앞으로 insert에 호출할 데이터는 vo에 다 넣어놔야한다.
// 컨트롤러로 이동 -> insert 할때 vo전달
System.out.println("MODEL(DAO): vo: " + vo); // 로그 보여주기 vo 출력
datas.add(new DrinkVO(PK++, vo.getName(), vo.getPrice(), vo.getCnt()));
// vo로 부터 이름받고, vo로 부터 가격받고, vo로 부터 재고받기
return true;
}
// 목록 출력 부분에서
// nullpointException 이 뜨는 이유
//★★★ java.lang.NullPointerException
//-> "주어(주체)"가 Null이어서 발생하는 이슈
//-> 메서드 앞의 주어가 Null이어서 발생하는 이슈
//-> aaa.bbbbb();에서 aaa가 Null이어서 발생하는 이슈
// 1. 전체목록 출력 => 그냥 내가가진 멤버변수 datas 반환
// 2. 검색결과 출력 => 이름을 보고, 그 이름을 가진 애들을 반환
// R
public ArrayList<DrinkVO> selectAll(DrinkVO vo) {
if (vo.getName() == null) {
//지금 주어 vo.뭐시기 에서 vo가 null이라서 NullPointerException 이 뜬것이다.
//사용자의 name이 검색을 안했어 ? // 만약에 그냥 전체목록출력이었다면
return datas; // 그럼 그냥 데이터를 반환해주고
} else {// 이름을 보고
ArrayList<DrinkVO> datas = new ArrayList<DrinkVO>();
// 새로운 datas를 만들어서,
// 검색 결과에 해당하는 애
for (DrinkVO data : this.datas) {//이름을 가진 애들을 넣어서 반환
if (data.getName().contains(vo.getName())) {// 검색이름이 data이름에 존재해 ?
// equals는 그 정확히 그 단어가 일치해야만 나온다
// 그래서 contains를 쓰기
datas.add(data);
}
}
return datas;
}
}
// R
public DrinkVO selectOne(DrinkVO vo) { // PK
for (DrinkVO data : datas) {
if (data.getNum() == vo.getNum()) { // 데이터를 받은 pk랑 입력받은 번호랑 일치하면
DrinkVO dVO = new DrinkVO(data.getNum(), data.getName(), data.getPrice(), data.getCnt());
// return 자리에 data가 들어가게 되면 ,, 원본이 자료를 받은 그대로 출력 되기때문에
// 원본 데이터에 손상이 올수도 있다는 에러가 떴다.
// 그래서 data를 그대로 반환 하는것이 아니라 그것과 똑같은 복사본을 만들어서
// 그 복사본을 반환 시킨다.
return dVO;
// 실제 DB 데이터(==datas)를 전송 xxxxx
// 새로 vo객체를 new(객체화)해서 전송 O
}
}
System.out.println(" 로그: selectOne(): 해당상품없음");
return null;
}
// 오버로딩이 불가능한 기능 일 경우,
// 기능이 매우 유사한 것이기 때문에 내부 로직에서 분리하여 관리
// -> 유사한 기능끼리는 묶어서 관리하는것이 용이하기 때문
// == 응집도를 높임 -> 유지보수에 용이
// 인자를 vo로 맞춰서 결합도를 낮추고 기능이 유사한 것을 한데 모아서 응집도를 높임
// 자바로만 했을 때의 최상급 코드
// U
public boolean update(DrinkVO vo) {
for (DrinkVO data : datas) {
if (data.getNum() == vo.getNum()) {
// 구매할때에는 절대값이랑 내 재고랑 비교
if (vo.getCnt() < 0) { // 구매할때
int cnt = vo.getCnt() * (-1); // 구매하려는 양
if (cnt > data.getCnt()) {
System.out.println(" 로그: update(): 재고없음");
return false;
}
}
data.setCnt(data.getCnt() + vo.getCnt());
// 보통 재고추가에 맞춰서 + 로 하고
// 구매를 하면 cnt를 빼주는 걸로 많이 쓴다.
System.out.println("data: " + data);
return true;
}
}
System.out.println(" 로그: update(): 해당상품없음");
return false;
}
// D
public boolean delete(DrinkVO vo) {
for (int i = 0; i < datas.size(); i++) {
if (datas.get(i).getNum() == vo.getNum()) {
datas.remove(i);
return true;
}
}
System.out.println(" 로그: delete(): 해당상품없음");
return false;
}
}
View - DrinkView
package view;
import java.util.ArrayList;
import java.util.Scanner;
import model.DrinkVO;
public class DrinkView {
private static Scanner sc=new Scanner(System.in);
public int tryCatch() {
while(true) {
try {
System.out.print("입력) ");
int action=sc.nextInt();
return action;
}
catch(Exception e) {
sc.nextLine();
System.out.println("정수로 입력해주세요!");
}
}
}
public int printMenu() {
System.out.println("=== 자 판 기 ===");
System.out.println("1. 음료추가");
System.out.println("2. 음료목록출력");
System.out.println("3. 음료구매");
System.out.println("4. 음료제거");
System.out.println("5. 음료재고추가");
System.out.println("6. 음료검색");
// "이" 라고 검색시 아이스크림,아이스티 등 띄우기 // selectAll(2개이상)
// R ->selectAll
System.out.println("7. 프로그램 종료");
while(true) {
int action=tryCatch();
if(1<=action && action<=7) {
return action; // "유효성 검사" == 사용자의 입력값 검사
// : 사용자의 입력값에 대하여 자료형(타입),범위 등을 확인하는 것
}
}
}
public String getDrinkName() { // 음료 이름 입력
System.out.print("음료이름 ");
String name=sc.next();
return name;
}
public int getDrinkCnt() { // 음료 재고 입력
System.out.print("음료재고입력) ");
int cnt=sc.nextInt();
return cnt;
}
public int getDrinkPrice() { // 가격입력
System.out.print("음료가격입력) ");
int price=sc.nextInt();
return price;
}
public void printDrinkList(ArrayList<DrinkVO> datas) { // 음료 목록 출력
if(datas.isEmpty()) {
System.out.println("출력할 음료가 없습니다...");
return;
}
for(DrinkVO v:datas) {
System.out.println(v);
}
}
public int getDrinkNum() { // 음료 번호 입력
System.out.print("음료번호입력) ");
int num=sc.nextInt();
return num;
}
public void printTrue() { // 서비스 완료
System.out.println("요청하신 서비스를 완료했습니다.");
}
public void printFalse() { // 서비스 실패
System.out.println("요청하신 서비스는 현재 이용이 어렵습니다.");
System.out.println("다음에 다시 이용해주시기 바랍니다.");
}
public void printEnd() { // 프로그램 종료
System.out.println("프로그램 종료...");
}
}
Controller - DrinkController
package ctrl;
import java.util.ArrayList;
import model.DrinkDAO;
import model.DrinkVO;
import view.DrinkView;
public class DrinkCtrl {
private DrinkView view;
private DrinkDAO dao;
public DrinkCtrl() {
view=new DrinkView();
dao=new DrinkDAO();
}
public void startApp() {
while(true) {// while문으로 한번 더 감쌌다.
// 장바구니가 종료되기 전까지 절대로 끝나지 않는 루프
System.out.println(" 로그: 사용자가 새로 입장합니다.");
// 장바구니를 설명하기 위해 고객이 접속한다는 뜻
// 로그
// : 확인을 위한 것
// : 실제 서비스에서는 출력 xxx
ArrayList<DrinkVO> cart=new ArrayList<DrinkVO>();
// 카트라는 공간을 하나 새로 만든다.
// 사용자가 새로 입장하면 장바구니가 초기화 돼야된다
// 장바구니의 타입은 ArrayList
// 장바구니 장바구니 = 초기화;
while(true) {
int action=view.printMenu();
if(action==1) { // 음료추가
String name=view.getDrinkName(); // 이름을 입력받고
int price=view.getDrinkPrice(); // 가격도 입력받고
int cnt=view.getDrinkCnt(); // 수량도 입력받고
DrinkVO vo=new DrinkVO(0,name,price,cnt);
// vo는 살짝 만들어서 쓰고 그다음에 쓰지 않는 친구
// pk는 지금 몰라서 그냥 0으로 설정
// 요렇게 선언 해주고 사용하기 // 인자 4개
// 전달하지않아도되는 값들은 0,null 등으로 설정
System.out.println("CTRL: vo: "+vo); // vo 로그 생성
// DAO의 CRUD에게 전달해야하는 값만 설정
if(dao.insert(vo)) { // DrinkVO의 vo라는 값에 추가해줘
view.printTrue(); // true면 성공
}
else {
view.printFalse(); // false면 실패
}
}
else if(action==2) { //음료 목록 추가
ArrayList<DrinkVO> datas=dao.selectAll(new DrinkVO(0,null,0,0));
// 목록에 반환되는 값은 없지만 null을 넣으면 에러가 뜨므로
// 필요한 값은 없지만 초기화 해주기
//전체 목록을 불러올건데
// 인자가 vo인데 로직에서 vo를 사용하지 않아서
// selectAll(vo 이지만 사용하는 게 없기 때문에)
// selectAll(null) null 값을 넣어준다.
// 초기값 pk =0, 이름 = null, 가격 = 0, 수량 =0 ;
view.printDrinkList(datas); // 저장된 데이터들을 forEach문으로 다 불러와줘
}
else if(action==3) { // 구매하기
int num=view.getDrinkNum(); // 음료 번호 입력 받기
int cnt=1; // 수량은 1로 정해놨다.
DrinkVO vo=new DrinkVO(num,null,0,-cnt);
// 전달하고자 하는 값만 넣어주면 된다.
// 보통 구매에서 수량을 구입하면 재고에서 빼줘야 하기 때문에
// -cnt라고 표현해준다
// 입력하면 구입할 시에 cnt를 빼줄수 있게
if(dao.update(vo)) {
// 구매에 성공했을때에만 장바구니에 해당 상품을 추가
// 구매에 성공 했다~~ 그러면
DrinkVO data=dao.selectOne(vo);
//모델에게 PK,name,price좀 줄래 ? 한데 묶은 data좀 줄래?
// data 하나 니까 selectOne
// 이때 selectOne 해서 나온 데이터는 자판기에 들어있는 재고가 저장이 되어있기 때문에
// data의 재고는 내가 원하던 재고로 맞춰줘야함
// data에 정보를 담아서 하나 가져와 //복사본을 가져왔다.
// 근데 복사본도 원본과 동일하므로 받아온 데이터를 그대로 출력한것
// 목록엔 콜라가 5개 있는데
// 나는 내가 구입한 1개의 콜라만 보여줘야 하므로
// 내가 가진 콜라 1개 짜리로 data를 다시 설정한다.
// data의 수량
data.setCnt(cnt);
// ★ PK,name,price는 자판기에 저장된 상품 정보로 가능하지만,
// ★ cnt는 사용자가 입력했던 정보로 변경해야함!
// 커스터마이징 할일이 없기때문에 flag 알고리즘을 사용
boolean flag=false; // 카트에 그게 있었는지 없었는지~
int index=0; // 인덱스 번호 변수 선언
for(int i=0;i<cart.size();i++) { //장바구니의 크기만큼
if(data.equals(cart.get(i))) { // 사용자가 선택한 제품이랑 카트 제품이 동일해?
//데이터 인덱스 번호 자리랑 카트에 고른 인덱스 번호랑 같은 상품일때
//연산자가 안되서 오버라이딩
index=i; //인덱스 위치를 기억 시켜놓으면 바로 추가하면 되니까
// 인덱스 번호는 몇번인지 //인덱스 번호 표시
flag=true; // true일때 작동 // 조건이 맞을때 작동
}
}
if(flag) {
// true 일때 이것도 true가 되면서
// 인덱스번호자리의 수량들을 다시 설정
// 같은 품목이니까 1-> 2로 수량이 쌓임
// 카트의 인덱스 번호 자리의 수량을 다시 설정
// 기존거 에서 + 수량을 추가
cart.get(index).setCnt(cart.get(index).getCnt()+cnt);
// 기존 수량에 추가한 수량을 더함
}
else {
// 혹시 cart에 없던 제품이었니 ? 그러면 add
cart.add(data); // 데이터에 담길거 : PK,name,price,cnt 알아야한다
// 근데 ! 기존 데이터에서 PK,name,price는 알아낼수 있는데
// cnt는 input 값에서 얻어낼수 있다.
// 장바구니.add(무엇을 샀는지 기입 : 내가 구매한 상품 넣기);
// 장바구니에는 담지만 내가 담은 항목이 서로 연관없는 다른 상품이라면
// 재고가 중첩되지않고 물건 1개, 물건 1개 이렇게 쌓임
// 단 , 내가 커스터마이징 할수 있는 제품은 1개, 1개 이렇게 쌓임
//ex)아메리카노 시럽없이, 아메리카노 얼음많이 등등
// 내가 구매한 상품을 차곡차곡
}
view.printDrinkList(cart); // 장바구니에 추가된 항목 보기
view.printTrue();
}
else {
view.printFalse();
}
}
else if(action==4) { // 음료 삭제
int num=view.getDrinkNum();
DrinkVO vo=new DrinkVO(num,null,0,0);
if(dao.delete(vo)) {
view.printTrue();
}
else {
view.printFalse();
}
}
else if(action==5) { // 재고 추가
int num=view.getDrinkNum();
int cnt=view.getDrinkCnt();// 재고추가는 입력한 만큼 더하는것
DrinkVO vo=new DrinkVO(num,null,0,cnt); //누구를 얼마만큼 추가할래 ?
if(dao.update(vo)) {
view.printTrue();
}
else {
view.printFalse();
}
}
else if(action==6) { // 음료 검색
String name=view.getDrinkName(); // 너 뭐 검색할래 ? 이름받기
// 그다음 출력하기
ArrayList<DrinkVO> datas=dao.selectAll(new DrinkVO(0,name,0,0));
view.printDrinkList(datas);
}
else if(action==7) { // 프로그램 종료
view.printEnd();
break;
}
}
System.out.println(" 로그: 사용자가 종료했습니다.");
cart.clear();
}
}
}
Client - DrinkClient
package client;
import controller.DrinkCtrl;
public class Client {
public static void main(String[] args) {
DrinkCtrl app=new DrinkCtrl();
app.startApp();
// 클라이언트는 이 코드로 고정 !
}
}
728x90
반응형
'JAVA > [실습문제]' 카테고리의 다른 글
| [실습문제] 회원 상품구매 MVC패턴 2 (0) | 2024.04.08 |
|---|---|
| [실습문제] 회원 상품구매 MVC패턴 (0) | 2024.04.08 |
| [실습문제] 포켓몬(추상클래스, private) (0) | 2024.04.08 |
| [실습문제] 상속 (응용문제) (0) | 2024.04.08 |
| [실습문제] 상속 (예제 만들기) (0) | 2024.04.08 |