자바풀스택 과정/자바 풀 스택 : 수업내용정리

자바 풀 스택 4/22 하루 기록 103(최종프로젝트 20일차)

파티피플지선 2025. 4. 22. 18:25

9:28 학원 도착

 

docker build -t hello-java .

. 은 해당 폴더의 파일들을 이용해서 이미지를 빌드하겠다는 의미

그 이미지는 Hello.java 파일을 실행하는 이미지이다.

 

 

컨테이너 안에서 어떤 프로세스가 시작이되고 종료되면 컨테이너도 같이 종료된다.

 

 

 

docker ps -a : 모든 컨테이너(종료된 컨테이너포함)들이 나타남(name은 도커 컨테이너 이름이고 이것은 검색을 하거나 설정하거나 할 때 필요한 고유값이어야 함)

java-hello를 실행할 때 docker 컨테이너 이름을 부여하지 않아서 무작위 이름(confident_spence, objective_boyd 같은)이 부여됨

 

 

 

컨테이너 실행할 때 이름을 부여하면서 실행하려면

docker run -d --name app1 hello-java2

docker run -백그라운드에서실행되게detached설정으로 --name 도커컨테이너의고유한이름  실행할이미지파일

 

 

docker logs app1

실행했던 기록을 불러오는 것.

 

docker container prune : docker 컨테이너 기록을 삭제 -> 이후 docker ps -a 하면 아무것도 나타나지 않는다.

 

 

 

 

 

docker run --name app2 hello-java3

Ctrl+C 하면 컨테이너도 종료됨.

 

docker logs -f app2 : 로그를 실시간으로 출력함

이때는 Ctrl C 를 누르면 로그만 종료됨.

docker logs -f --tail 10 app2 : 로그를 최근 거 10개를 꼬리 물고 와서 실시간으로 출력함

마찬가지로 Ctrl C를 누르면 도커는 종료되지 않고 로그만 종료됨.

 

docker stop app2를 하면 백그라운드에서 실행되던 도커가 종료되고

다시 docker ps -a 하면 실행되었던 모든 도커 이름이 나타나고

docker rm app2 -> app2 도커를 제거

docker rm app1 -> app1 도커를 제거

 

 

도커에서 이미지를 실행하려면 docker images로 image 이름을 찾아서 docker run -d --name 도커이름 실행할이미지이름 을 입력하면 된다.(계속 같은거를 다시 쓰고 다시 쓰고 있지만 이러면 확실해진다!)

 

 

CentOS 안에서 app1이라는 이름의 컨테이너가 있고 app1에서는 jdk환경과 hello.class 파일이 있어서 도커를 실행시키면 자바 파일도 실행된다.

 

docker exec -it app1 bash라고 입력하면 컨테이너 환경으로 들어간다.

 

컨테이너 환경에서 java 를 입력하면 반응이 있고,

java --version을 입력하면 자바의 버젼까지 확인이 가능하다. 

 

 

컨테이너의 내용은 dockerfile 때문에 가능해졌다.

 

컨테이너에서 CentOS로 빠져나올 때는 exit

컨테이너로 들어갈 때는 docker exec -it  컨테이너명 bash

-it 의 의미는 interactive(명령어로 입력하여 상호작용할 수 있는 공간으로 들어간다는 의미인듯)

                  +terminal 터미널에서 입력할 수 있도록 터미널로 연결된다는 의미인듯

 

 

 

 

docker run --name app1 -d -it hello-java3 입력해보기

 

 

 

 

현재 디렉토리의 모든 내용을 COPY . . 했기 때문에.

앞의 쩜은 현재 디렉토리의 모든 것을 뒤의쩜 작업디렉토리에 모두 넣었다.

 

 

하지만 설정 파일이나 안 넣고 싶은 파일이 있을 수도 있잖아.

그럴 때는 .dockerignore (.gitignore 와 비슷한 역할)에 빼고 싶은 파일들을 적어둔다.

즉, .dockerignore는 docker로 build 할 때 무시할 파일이나 폴더를 명시해놓으면 알아서 제외되고 이미지가 만들어진다.

 

그러면 docker 컨테이너 안에서 확인되지 않는다.

 

 

 

 

과제 

1. Spring04_Thymeleaf 프로젝트를 빌드해서 xxx.jar 파일을 얻어낸다.

2. 얻어낸 jar 파일의 이름을 spring.jar 파일로 이름을 변경한다.

3. Linux에서 /home/docker-test/spring폴더를 만든다.

4. /home/docker-test/spring 폴더 안에 spring.jar 파일을 넣는다.

5. 위 폴더 안에서 jdk 환경에서 spring.jar를 실행할 수 있는 이미지를 생성할 Dockerfile을 생성한다.

6.생성된 Dockerfile을 이용해 spring-image라는 이름의 이미지를 build 한다.

7. Spring-image를 이용해서 spring-app이라는 이름의 container로 백그라운드로 실행한다.

   단, port 번호는 9000:9000설정이 적용되도록. -> 이부분은 모르겠다. -> 전에 작성한 포스트 참고해서 하고 있다.

docker run -d --name oracle11g -p 1521:1521 -p 8080:8080 -e ORACLE_ALLOW_REMOTE=true -e ORACLE_PASSWORD=oracle oracleinanutshell/oracle-xe-11g

8. 실행후 firewall-cmd를 이용해서 9000포트를 열고 웹브라우저로 http://아이피주소:9000/spring04 요청을 해서 index페이지가 응답되는지 확인한다.

 

 

왜 안되나 했더니 6번에서 이미지 만든게 바보같이 java 폴더에서 해서 ㅠㅠㅠㅋㅋㅋㅋㅋㅋㅋㅋ

spring 폴더로 와서 다시 하는 중.

 

어쩐지.... 그래 빌드부터 이렇게 길었어야 하지...

 

 

 

빌드중에 샘이랑 같이 하는 중(ls -l은 생략)

cd /home/docker-test/spring

mv Spring어쩌구긴이름.jar spring.jar

 

docker build -t spring-image .  ->이미지 생성됨

docker run -d --name spring-app4 -p 9000:9000 spring-image2

 

계속 안돼서 왜 안되나 했더니

CMD ["java", "-jar", "spring.jar"]여야 하는데 "spring"으로 했어서!!!

다시 해봐야지.

 

 

아 된다...ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ ㅠㅠ 바부팅 ㅠ 이제 절대 안까먹겟따!! ㅋㅋㅋ

 

 

<오전: 프로젝트 진행>

내가 볼 테이블들만 정리

// 유저+매점 테이블, 본사직원은 storenum, storename, storecall NULL
Table tb_user {
  userid number [pk, note: "사용자의 고유번호 시퀀스"]
  storename varchar2(20) [unique, note: "어디 지점인지"]
  storecall varchar2(20) [note: "학원 전화번호"]
  id varchar2(20) [note: "유저 아이디"]
  userpwd varchar2(20) [note: "유저 비밀번호"]
  pwdstatus number [default: 1, note: "0이면 비밀번호 수정한거"]
  username varchar2(20) [note: "유저 이름"]
  role varchar2(20) [ref: > tb_acode.acode, note: "ROLE"]
  phone varchar2(20) [note: "유저 전화번호"]
  deleted varchar2 [default: "NO", note: "NO->재직중, YES->퇴사"]
}
// 각 호점 학원에서 운영하는 강의들의 수업 테이블
Table tb_class {
  classid number [pk, note: "수업의 고유번호 시퀀스"]
  classname varchar2(50) [note: "수업명"]
  lectureid number [ref: > tb_bcode.bcode, note: "LECTURE"]
  storename varchar2(20) [ref: > tb_user.storename]
  description clob [note: "수업에 대한 상세 설명"]
  teacherid number [ref: > tb_teacher.teacherid, note: "맡은 강사의 고유번호"]
  startdate date [note: "수업이 시작하는 날짜"]
  enddate date [note: "수업이 끝나는 날짜"]
  starttime date [note: "수업이 시작하는 시간"]
  endtime date [note: "수업이 끝나는 시간"]
  maxstudent number [note: "수업의 최대 인원"]
  status varchar2(20) [ref: > tb_bcode.bcode, note: "CLS"]
  weekday varchar2(20) [note: "수업 요일"]
  price number [note: "수업의 가격"]
}

// 학생이 어떤 수업을 듣는지 보는 중간 테이블
Table tb_student_class {
  studentid number [ref: > tb_student.studentid]
  classid number [ref: > tb_class.classid]
}
//지점에서 보는 매출 테이블
Table tb_adminsale {
  adminsaleid number [pk, note: "고유번호 시퀀스"]
  storename varchar2(20) [ref: > tb_user.storename]
  credate date [note: "매출 날짜"]
  editdate date [note: "매출 수정 날짜"]
  salename varchar2(20) [note: "매출 항목"]
  price number [note: "총 금액"]
  acode varchar2 [ref: > tb_acode.acode, note: "구분"]
  bcode varchar2 [ref: > tb_bcode.bcode, note: "구분 상세"]
  auto varchar2 [default: 'YES', note: "NO->지점 담당자가 직접 넣었을 때"]
}
// 본사에서 제공하는 발주 품목 테이블
Table tb_product {
  productid number [pk, note: "품목 고유번호 시퀀스"]
  productname varchar2(255)
  category varchar2(50) [ref: > tb_bcode.bcode, note: "PRODUCT"]
  price number [note : "가격 -> 수정가능"]
  deleted varchar2(10) [default: 'NO', note: "YES -> 발주 품목에서 제거됨" ]
}
// 지점에서 본사로 보낼 발주 목록
Table tb_order {
  orderid number [pk, note: "발주 명세서의 고유번호 시퀀스"]
  name varchar2(20) [note: "발주한 사람 이름"]
  storename varchar2(20) [ref: > tb_user.storename]
  credate date [default: 'SYSDATE', note: "발주 처음 요청 날짜"]
  editdate date [default: 'SYSDATE', note: "발주 수정 날짜"]
  rejdate date [default: `SYSDATE`, note: "본사에서 발주 반려된 날짜"]
  orddate date [default: "SYSDATE", note: "마지막 발주 요청 결과 날짜"]
  status varchar2(20) [ref: > tb_bcode.bcode, note: "ORDER"]
  memoreply varchar2(500)
  memorequest varchar2(500)
  totalprice number [note: "지점에서 본사로 보낼때 프론트에서 값을 구해서 요청할 때 insert"]
}
// 지점에서 발주 목록에 추가할 품목 테이블
Table tb_order_detail {
  orderdetailid number [pk, note: "각 발주 품목의 고유 번호"]
  orderid number [ref: > tb_order.orderid]
  productid number [ref: > tb_product.productid]
  quantity number
  price number [ref: > tb_product.price, note: "개당 가격"]
}

 

SalesMapper랑 mapper 만들던 중에 Dto 부터 만듦

package com.example.FinalProject.dto;

import lombok.Data;

@Data
public class SalesDto {
	int adminsaleid;//지점 adminsale 고유번호
	int ceosaleid;//본사 ceosale 고유번호
	int storenum;//매장번호 = tb_user.storename
	String salename;//매출 항목
	String credate;//매출 날짜
	String editdate;//매출 수정 날짜
	int price;//항목 금액
	String acode;//구분코드 : 수입/지출
	String bcode;//상세구분코드 : 수업료수입, 기타수입,강사월급, 발주비용, 기타지출
	String auto;//default: yes(발주나 수업에서 처리됨), no: 담당자가 직접 입력

	//쿼리문 관련
	int totalprofit;//총수입
	int totalcost;//총지출
	int totalprice;//총금액
	String sdate;//문자열로 변환된 date 타입의 data
	String smonth;//상동  
	String syear;//상동
	//수업 관련 : tb_class, tb_student_class
	String clsstatus;//수업 상태 : 진행중
	int classid;//수업 고유 번호
	int clsprice;//수업료
	int studentcount;//학생 수
	
	//발주 관련 :tb_product, tb_order, tb_order_detail
	int orderid;//발주고유번호
	int orderstatus;//발주상태
	int orderdetailid;//발주 품목의 고유번호
	int productid;//tb_product.productid
	int quantity;//수량
	int productprice;//개당 가격
	int productname;//품목 이름
	
	

}

SalesMapper 만드는 중. CEO 측은 내 파트 아니어서 일단 내 파트에서 필요한 기능은 이정도 되는 것 같은...데.

package com.example.FinalProject.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.example.FinalProject.dto.SalesDto;

@Mapper
public interface SalesMapper {
	//Admin 측
	//지점번호와 bcode를 읽으면
	List<SalesDto> getAdminSalesList(@Param("storenum") int storenum, @Param("bcodes") List<String> bcodes);
	SalesDto getAdminSalebyId(int adminsaleid);
	int insertAdminSales(SalesDto dto);
	int editAdminSales(SalesDto dto);
	int deleteAdminSales(int adminsaleid);//
	//발주가 "승인"일 때 발주 비용 추가하는 메소드(발주에서 사용)
	int insertOrderApprovedCost(SalesDto dto);
	//수업이 '진행중'일 때 수업료 수입을 추가하는 메소드(수업에서 사용)
	int insertClsIngProfit(SalesDto dto);
	//연도별 수입 데이터 불러오기
	List<SalesDto> getAdminProfitStatbyYear();
	//연도별 지출 데이터 불러오기
	List<SalesDto> getAdminCostStatbyYear();
	//연도별 과목별 데이터 불러오기
	List<SalesDto> getAdminSalesStatbyLectYearly();
	//연도의 월별 과목별 데이터 불러오기
	List<SalesDto> getAdminSalesStatbyLectMonthly();
	
	//Ceo측
	
}

 

 

 

<오후 : 프로젝트 진행>

깃허브에 내가 작업하는부분만 포트폴리오 용으로 만들고 싶어서 왔다 갔다 하다가 이전에 했던거랑 자꾸 중복되고,

이번에 멘토링 후 조장님이 올린거는 gemini API도 포함되어 있고 그래서 그냥 이전에 하던 환경에서 수정내용 반영해서 하려고 함.

 

로그인은 나중에 처리하고 일단 내가 만든 화면 UI 좀 손봐야겠다.

맵퍼 작성 중에 발주와 수업과 연관된 맵퍼는 다른 맵퍼들이 만들어진 다음에야 어느정도 활용 가능할 수 있는 것 같다.

일단 보류하고 남은 한시간은 내가 좋아하는 프론트 하다 가야징 ㅎㅎ

 

프론트 자꾸 사이드바가 공중에 떠있어서 우리가 참고하기로 한 프로젝트 분석했는데 진짜 대박적.

우리가 배운 방식이랑 다르게 라우터를 두지 않고 currentMenu를 둬서 진행함. 이걸 우리꺼에 잘 적용을 해봐야겠다.

 

 

오늘 한 거 최종

package com.example.FinalProject.dto;

import lombok.Data;

@Data
public class SalesDto {
	int adminsaleid;//지점 adminsale 고유번호
	int ceosaleid;//본사 ceosale 고유번호
	String storename;//매장번호 = tb_user.storename
	String salename;//매출 항목
	String credate;//매출 날짜
	String editdate;//매출 수정 날짜
	int price;//항목 금액
	String acode;//구분코드 : 수입/지출
	String bcode;//상세구분코드 : 수업료수입, 기타수입,강사월급, 발주비용, 기타지출
	String auto;//default: yes(발주나 수업에서 처리됨), no: 담당자가 직접 입력

	//쿼리문 관련
	int totalprofit;//총수입
	int totalcost;//총지출
	int totalprice;//총금액
	String sdate;//문자열로 변환된 date 타입의 data
	String smonth;//상동  
	String syear;//상동
	//수업 관련 : tb_class, tb_student_class
	String clsstatus;//수업 상태 : 진행중
	int classid;//수업 고유 번호
	int clsprice;//수업료
	int studentcount;//학생 수
	
	//발주 관련 :tb_product, tb_order, tb_order_detail
	int orderid;//발주고유번호
	int orderstatus;//발주상태
	int orderdetailid;//발주 품목의 고유번호
	int productid;//tb_product.productid
	int quantity;//수량
	int productprice;//개당 가격
	int productname;//품목 이름
	
	

}

 

package com.example.FinalProject.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.example.FinalProject.dto.SalesDto;

@Mapper
public interface SalesMapper {
	//Admin 측
	//지점번호와 bcode를 넣어서 수입/지출 리스트를 가져오기
	List<SalesDto> getAdminSalesList(@Param("storenum") int storenum, @Param("bcodes") List<String> bcodes);
	SalesDto getAdminSalebyId(int adminsaleid);
	int insertAdminSales(SalesDto dto);
	int editAdminSales(SalesDto dto);
	int deleteAdminSales(int adminsaleid);//
	//발주가 "승인"일 때 발주 비용 추가하는 메소드와 관련 메소드(발주에서 사용)
	int insertOrderApprovedCost(SalesDto dto);
	int countByClassId(@Param("classid") int classid);
	int getPriceByClassId(@Param("classid") int classid);
	String getNameByClassId(@Param("classid") int classid);
	//수업이 '진행중'일 때 수업료 수입을 추가하는 메소드와 관련 메소드(수업에서 사용)
	int insertClsIngProfit(SalesDto dto);
	//연도별 수입 데이터 불러오기
	List<SalesDto> getAdminProfitStatbyYear();
	//연도별 지출 데이터 불러오기
	List<SalesDto> getAdminCostStatbyYear();
	//연도별 과목별 데이터 불러오기
	List<SalesDto> getAdminSalesStatbyLectYearly();
	//연도의 월별 과목별 데이터 불러오기
	List<SalesDto> getAdminSalesStatbyLectMonthly();
	
	//Ceo측
	
}

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.SalesMapper">

	<select id="getAdminSalesList" parameterType="map" resultType="AdminSale">
	  SELECT *
	  FROM tb_adminsale
	  <where>
	    storename = #{storename}
	    <if test="bcodes != null and bcodes.size() > 0">
	      AND bcode IN
	      <foreach item="bcode" collection="bcodes" open="(" separator="," close=")">
	        #{bcode}
	      </foreach>
	    </if>
	  </where>
	  ORDER BY credate DESC
	</select>
	<select id="getAdminSalebyId">
		select * from tb_adminsale
		where adminsaleid=#{adminsaleid}
	</select>
	<insert id="insertAdminSales">
		insert into tb_adminsale
		(adminsaleid, storename, credate, editdate, salename, price, acode, bcode, auto)
		values 
		(adminsale_seq.nextval, #{storename}, sysdate, sysdate, #{salename}, #{price}, #{acode}, #{bcode}, 'NO' )				
	</insert>
	<update id="editAdminSales">
		update tb_adminsale
		set (storename=#{storename}, editdate=sysdate, salename=#{salename}, 
		     price=#{price}, acode=#{acode}, bcode=#{bcode}, auto='NO')
		where adminsaleid=#{adminsaleid}
	</update>
	<delete id="deleteAdminSales">
		delete from tb_adminsale
		where adminsaleid=#{adminsaleid}
	</delete>
	<insert id="insertOrderApprovedCost">
		insert into tb_adminsale
		(adminsaleid, storename,credate,editdate, salename,price, acode, bcode,auto)
		values 
		(adminsale_seq.nextval,#{storename}, sysdate, sysdate, #{salename}, #{price}, #{acode}, #{bcode}, 'YES') 
	</insert>
	<select id="countByClassId" resultType="int">
	  SELECT COUNT(*) 
	  FROM tb_student_class 
	  WHERE classid = #{classid}
	</select>
	<select id="getPriceByClassId" resultType="int">
	  SELECT price 
	  FROM tb_class 
	  WHERE classid = #{classid}
	</select>
	<select id="getNameByClassId" resultType="string">
	  SELECT classname 
	  FROM tb_class 
	  WHERE classid = #{classid}
	</select>
	
</mapper>

 

 

package com.example.FinalProject.service;

public interface SalesService {
	public void insertRevenueByClass(int classid, String storename, String acode, String bcode); 
}

 

package com.example.FinalProject.service;

import org.springframework.beans.factory.annotation.Autowired;

import com.example.FinalProject.dto.SalesDto;
import com.example.FinalProject.mapper.SalesMapper;

public class SalesSerivceImpl implements SalesService{
	@Autowired SalesMapper salesmapper;
	@Override
	public void insertRevenueByClass(int classid, String storename, String acode, String bcode) {
//		int studentCount = studentClassMapper.countByClassId(classid);
//	    int classPrice = classMapper.getPriceByClassId(classid);
//	    String classname = classMapper.getNameByClassId(classid);
	    
//	    String salename = classname + " 수업 수익";
//	    int totalRevenue = studentCount * classPrice;

//	    SalesDto dto = new SalesDto();
//	    dto.setStorename(storename);
//	    dto.setSalename(salename);
//	    dto.setPrice(totalRevenue);
//	    dto.setAcode(acode);
//	    dto.setBcode(bcode);

//	    salesmapper.insertOrderApprovedCost(dto);
		
	}

}

 

......

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ하... 내일은 대학원 시험때문에 못나올거 같고, 낼 모레 이어서 해보자....