[조건문의 문법] 1) IF - if(true) => result : true => 실행 - if(false) => result : false => 실행되지 않음
2) ELSE - if 조건문에 해당하지 않은 경우 실행되지 않음
3) ELSE IF - if 조건문 다음에 오는 조건문
[조건문의 응용] - if(true) : 항상 실행되는 조건이기에 올바르지 않음 - prompt('질문내용'); : 입력창을 통해 사용자로부터 정보를 입력받을 수 있음
2. 반복문
- (Loop, Iterate) 반복적인 작업을 지시하는 방법
1) while while(boolean){ 반복해서 실행할 코드 } - 조건이 true에서 false가 될때까지 실행 (조건이 만족하면 실행) - while(true) : 무한한 반복을 의미하므로 가급적 사용X - while (i < 10) : i의 값이 10보다 작다면 true, 아니면 false, i 값이 10이 되면 종료
2) for for(초기화; 반복조건(true/false); 반복이 될 때마다 실행되는 코드){ 반복해서 실행될 코드 }
[반복문의 제어] - break : 반복문의 종료 - continue : 다음 코드 실행하지 않고 다음 증감값으로 이동 (반복문을 종료하지 않음)
[반복문의 중첩] for(i=0; i<10; i++){ for(j=0; j<10; j++){ 반복해서 실행할 코드 } }
[변수] - JavaScript에서 변수는 var로 시작 (변수 선언의 의미) - 특수문자를 제외한 모든 문자로 시작 가능 - 한번 선언한 이후에는 또 var를 안붙여도됨 - 숫자, 문자의 연산이 모두 가능함
[변수의 효용] - 변수를 쓰기 전 : 모든 영역이 변할 수 있는 영역 alert(100+10); // 100을 고치기 위해서는 모든 줄을 다 고쳐줘야함 alert((100+10)/10); alert(((100+10)/10)-10); alert((((100+10)/10)-10)*10); - 변수 사용 후 : 첫 줄은 변할 수 있는 영역, 나머지 줄은 변하지 않는 영역 a = 100; // 한번만 고치면 됨 a = a + 10; alert(a); a = a / 10; alert(a); a = a - 10; alert(a); a = a * 10; alert(a); - 변수를 사용하지 않으면 실수가 나올 수 있고 효율이 떨어지므로 유지보수력이 떨어지는 좋지 않은 코드가 됨
2. 비교 연산자
[연산자] - 어떤 작업을 컴퓨터에 지시하기 위한 기호
[대입 연산자 =] - a(변수) =(대입 연산자) 1(상수 : 고정된 값. 변수에 대응되는 개념) - 우항의 값을 좌항의 변수에 대입할때 사용
[동등 연산자 ==] - equal operator - 좌항과 우항을 비교해서 값이 같다면 true 다르다면 false - 값의 자료형보다 의미가 같으면 같다고 판단 - 숫자 1을 true로 간주, 1 외의 숫자들을 false로 간주
[일치 연산자 ===] - strict equal operator - 좌항과 우항이 정확하게 같을 때 true 다르다면 false - 정확하다는 의미 : 데이터형까지 같은 경우
- ORM을 사용하기 위한 인터페이스를 모아둔 것이며, JPA를 사용하기 위해서는 JPA를 구현한 Hibernate, EclipseLink,
DataNucleus같은 ORM 프레임워크를 사용해야 함
* ORM : 객체와 DB를 연결해주는 기술
1) spring.jpa.hibernate.ddl-auto 옵션 - create : 새로운 테이블 생성 - createdrop : 기존 테이블을 지우고 새로 생성 - none : 수동으로 직접 테이블을 생성해야함 - update : 현재 테이블 있으면 만들지 말고 데이터 누적. 테이블이 없으면 새로 생성(많이 사용).
시작 시 도메인과 스키마 비교하여 필요한 컬럼 추가 등의 작업 실행. 데이터는 삭제하지 않음. - validate : 기존과 새로운 것의 달라진 내용만 표시해줌. 스키마가 적합한지 검사함. 문제가 있으면 예외 발생.
2) spring.jpa.properties.hibernate.format_sql 옵션 - 콘솔에 sql 코드 보여질 때 문단 정리
3) spring.jpa.show-sql 옵션 - 실행했을 때 콘솔에 sql 코드 보여지기
//2.엔티티를 DB에 저장하기 Article target = articleRepository.findById(article.getId()).orElse(null); // DB에서 기존 데이터 가져오기 if (target != null) { // 기존 데이터가 있는지 확인하고 있으면 udpate articleRepository.save(article); }
//3.수정 후 결과 페이지로 이동하기 return "redirect:/articles/"+article.getId(); // return "redirect:/articles/"; // 목록으로 }
@GetMapping("/article/{id}/delete") public String delete(@PathVariable Long id) { //1. 삭제할 대상을 가져오기 Article article = articleRepository.findById(id).orElse(null);
//2. 대상 엔티티를 삭제하기 if (article != null) { articleRepository.delete(article); }
//3. 삭제 후 목록 페이지로 이동하기 return "redirect:/articles"; }
2. 특수 쿼리문 (직접 쿼리문 작성)
▶ ArticleRepository.java
@Transactional // 직접 쿼리 작성할때 반드시 필요 @Modifying(clearAutomatically = true) @Query(value="update article set content='kkk' where id = :id", nativeQuery=true) // :id는 값을 전달 받게됨 int updateTest(@Param("id")Long id);
▶ ArticleController
@GetMapping("/") public String index() { int res = articleRepository.updateTest(1L); return "index"; }
#mybatis mybatis.type-aliases-package=com.example.test.dto // alias가 등록되어있는 장소 mybatis.mapper-locations=/mybatis/**/*-mapper.xml // mapper.xml로 끝나는 파일 위치 mybatis.configuration.map-underscore-to-camel-case=true
▶ 맨 하단에 -javaagent:D:\fintechkmy\springboot\sts-4.24.0.RELEASE\lombok.jar 이렇게 수정
(경로에 한글이 있으면 STS 실행 안됨)
▶ STS DTO 파일로 돌아와서 @Data 추가하면 Outline에 Getter, Setter 메서드 모두 추가 되는 것을 알 수 있음
@Getter 추가하면 Getter 메서드만 추가됨
2) Anotation
(1) @ToString
- 디버깅 및 로깅 편의성 : @ToString 어노테이션을 사용하면 엔티티 객체의 문자열 표현을 쉽게 생성. 이는 디버깅 및 로깅 시 객체의 상태를 쉽게 확인할 수 있어 유용함. - 코드 간결성 : @ToString 어노테이션은 롬복(Lombok) 라이브러리에서 제공하는 기능임. 엔티티 클래스에서 직접 toString 메서드를 작성할 필요 없이 자동으로 생성해줌. 이는 코드의 간결성과 가독성을 높여줌. - 주의사항 - 엔티티 간의 양방향 연관 관계가 있는 경우, @ToString 어노테이션이 순환 참조를 일으킬 수 있음. - 이로 인해 StackOverflowError가 발생할 수 있음. 양방향 연관 관계가 있는 필드를 toString 메서드에서 제외해야함. - 롬복의 @ToString 어노테이션은 exclude 속성을 사용하여 특정 필드를 제외할 수 있음.
(2) @EqualsAndHashCode
- 롬복(Lombok) 라이브러리에서 제공하는 기능으로, 클래스의 모든 필드를 기준으로 equals 및 hashCode 메서드를 생성. - 주로 객체의 동등성 비교와 해시 기반 컬렉션(예: HashSet, HashMap)에서 사용. - 수동으로 작성해야 할 boilerplate 코드를 줄이고 코드의 가독성과 유지보수성을 높여줌
(3) @NoArgsConstructor
- Test() : 디폴트 생성자를 만들어줌
(4) @AllArgsConstructor - Test(String, String, String) : 전체 매개변수가 들어간 생성자를 만들어줌
(테스트 예제)
File ▶ New ▶ Spring Starter Project
▶ Name : test3 / Group : com.example.test3 / Artifact : test3 / Package : com.example.test3 ▶ Lombok, DevTool, Sprig Web 선택 ▶ com.example.test3 패키지 ▶ Test.java 클래스 생성
▶ Test.java
public class Test { private String id; private String name; private String cname; }
▶ STS - Windows - Show view - Outline에 보면 멤버변수만 있음
▶ Test.java
@Data public class Test { private String id; private String name; private String cname; }
https://spring.io/ ▶ Projects메뉴 ▶ Spring tool 4 ▶ 4.24.0 - Windows X86_64 설치(spring-tool-suite-4-4.24.0.RELEASE-e4.32.0-win32.win32.x86_64.self-extracting.jar) ▶ spring boot 폴더 만들어서 여기에 압축 풀기 ▶ contents.zip 압축 여기에 풀기 ▶ sts-4.24.0.RELEASE폴더 ▶ SpringToolSuite4.exe 가 실행파일임
파일 ▶ NEW ▶ Spring Starter Project ▶ Name test로 변경, Type Maven으로 변경, Packaging War로 변경, Java version 21로 변경, Group com.example.test로 변경, pacakge com.example.test로 변경 ▶ Dependencies 단계에서 맨아래 Web클릭 후 Spring Web 체크 ▶ Finish
* resources ▶ static : CSS 같은 정적 코드 위치 * application.properties : 설정값 작성 * src ▶ main ▶ webapp : War
2. JSP 설치
부트는 JSP를 기본적으로 지원 안함. 별도 설치 필요. Help ▶ Eclipse MarketPlace ▶ jsp 검색 ▶ Eclipse EnterPrise Java and Web Developer Toos 3.33 설치 ▶ Confirm ▶ Accept 선택 Finish ▶ Trust Artifacts 단계에서 Select All 클릭 후 Trust Selected 클릭 ▶ Restart 클릭
webapp 폴더 안에 WEB-INF 폴더 생성 ▶ 그 안에 view 폴더 생성
src/main/java 우클릭 패키지 com.example.test.controller 입력해서 생성 ▶ 패키지 안에 HomeController 클래스 생성 ▶ 컨트롤러 세팅
@Controller public class HomeController {
@RequestMapping("/") @ResponseBody public String home() { return "hello, Spring boot!!"; } }
▶ Run - Spring boot app로 실행해서 에러 안뜨면 세팅 성공 ▶ 브라우저에 http://localhost:8080/치면 출력 잘됨 * 톰캣이 내장되어있어서 실행 가능
@RequestMapping("/list.do") public String list(Model model) { List<StudentDTO> list = studentMapper.listStudent(); model.addAttribute("listStudent", list); return "list"; }
@GetMapping("/insert.do") public String insertForm(){ return "insert"; }
@PostMapping("/insert.do") public String insert(@ModelAttribute StudentDTO dto){ int res = studentMapper.insertStudent(dto); return "redirect:welcome"; }
@GetMapping("/delete.do") public String deleteForm(){ return "delete"; }
@PostMapping("/delete.do") public String delete(@RequestParam String id){ int res = studentMapper.deleteStudent(id); return "redirect:welcome"; }
@GetMapping("/find.do") public String findForm() { return "find"; }
@PostMapping("/find.do") public String find(Model model, @RequestParam String name){ List<StudentDTO> list = studentMapper.findStudent(name); model.addAttribute("listStudent", list); return "list"; } }
StudentMapper
@Service public class StudentMapper {
@Autowired private SqlSession sqlSession;
public List<StudentDTO> listStudent(){ return sqlSession.selectList("listStudent"); }
public int insertStudent(StudentDTO dto) { return sqlSession.insert("insertStudent", dto); }
public int deleteStudent(String id) { return sqlSession.delete("deleteStudent", id); }
public List<StudentDTO> findStudent(String name){ return sqlSession.selectList("findStudent", name); }
}
student-mapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mybatis.student.student-mapper"> <select id="listStudent" resultType="StudentDTO"> select * from student </select>
<insert id="insertStudent" parameterType="StudentDTO"> insert into student values(#{id}, #{name}, #{cname}) </insert>
<delete id="deleteStudent" parameterType="String"> delete from student where id=#{id} </delete> <select id="findStudent" parameterType="String" resultType="StudentDTO"> select * from student where name = #{name} </select> </mapper>
github.com 접속 ▶ 회원가입 ▶ 로그인 ▶ Create a new repository ▶ Repository name : test-repo1 ▶ public 체크 ▶ Add a Readme file ▶ 등록하고 나서는 URL https://github.com/minpoooh/test-repo1치고 들어올 수도 있음
2. Repository 삭제
Settings ▶ Danger Zone ▶ Delete this repository
3. 공개키와 개인키 생성
드라이브 ▶ 폴더 우클릭 ▶ Open Git Bash Here ▶ ssh-keygen 입력 ▶ /c/Users/user/.ssh 키가 저장되는 위치 나옴(들어가보면 파일이 두개 있음) ▶ 엔터 ▶ 엔터 ▶ 엔터 ▶
4. 소스트리 개인키 설정
소스트리 실행 ▶ 도구 ▶ SSH키 추가 ▶ 개인키 파일 선택 ▶ 열기 ▶ 옵션 ▶ SSH 클라이언트 설정 ▶ SSH 클라이언트를 OpenSSH로 변경
5. 깃허브 공개키 설정
깃 허브 ▶ 프로필 ▶ Settings ▶ SSH and GPG keys ▶ New SSH Key ▶ Title에 아무거나 넣고 Key에 .pub 키 파일 메모장으로 열어서 있는 내용 다 복사해서 붙여넣기 ▶ Add SSH Key
6. 소스트리와 깃허브 연결
소스트리 ▶ New Tab ▶ Remote 탭 ▶ 계정 추가 ▶ 호스팅 서비스 : Github, 선호 프로토콜 : SSH , OAuth 토큰 새로고침 클릭 ▶ 로그인 ▶ 맨 하단에 Authorize atlassian 버튼 클릭 ▶ 소스트리 돌아오면 인증성공 처리됨 ▶ 확인 ▶ 원격저장소에 깃허브 계정 올라오고 새로고침 누르면 test-repo1 올라와있는거 확인 가능
7. Clone
- 원격저장소에 있는 전체파일을 소스트리로 세팅하기
https://github.com/namhyung/uftrace 접속해보면 만들어져있는 파일들이 있음 ▶ <> Code 버튼 클릭 ▶ SSH 탭 ▶ 주소 복사 ▶ 소스트리 ▶ Clone 탭 ▶ 소스경로에 붙여넣기 ▶ 내경로에 내 드라이브 폴더 선택 ▶ 클론 버튼 클릭
8. Push
- 내가 드라이브에서 수정한 파일과 내용을 원격저장소에도 반영해주기
깃허브 ▶ <> Code ▶ SSH ▶ 주소 복사 ▶ 소스트리 ▶ New Tab ▶ Remote ▶ 저장소에 있는 test-repo1 Clone 클릭 ▶ 클론 버튼 클릭 ▶ 소스트리 탐색기 ▶ 클릭하면 폴더 생성된거 확인 가능함 ▶ 소스트리 설정 ▶ origin이라는 이름으로 받아오는 원격저장소 주소가 나옴
드라이브에 a.txt 추가하고 커밋하면 History에 origin이라고 나오는건 원격저장소, main은 내 드라이브 ▶ 소스트리 Push 버튼 클릭 ▶ Push 버튼 클릭 ▶ push 누르면 main, origin이 같은 위치로 변경됨 ▶ 깃허브 들어와서 Commit 클릭 ▶ a.txt파일 올라온거 확인 가능함
깃허브 ▶ Settings ▶ Collaborators ▶ 비밀번호 입력 ▶ Add people ▶ 협업할 사람 이름 넣기 ▶ 초대 메일 전송 ▶ view invitation 에서 수락한 후 초대 받은 사람이 소스트리에서 New tab ▶ Clone ▶ 브랜치 생성 ▶ 작업 ▶ 커밋 ▶ PUSH ▶ PUSH 된 내용 PULL 받아서 사용
로컬저장소 ▶ create ▶ 폴더 선택 ▶ 예 ▶ 해당폴더 들어가서 숨긴항목 봤을때 .git 폴더 있는지 확인 ▶ 폴더에 a.txt b.txt c.txt 파일만들기 ▶ 소스트리에 파일들 올라와있음 ▶ 모두 스테이지에 올리기 ▶ 하단에 첫번째 커밋 <br> a.txt, b.txt, c.txt추가 작성 후 커밋 클릭 ▶ 파일탐색기에서 a.txt에 아무내용이나 적고 c.txt는 삭제 ▶ 소스트리 파일상태에서 모두 스트이지 올리기 ▶ 두번째 커밋 <br> a.txt 수정 b.txt 삭제 작성 후 커밋 클릭 ▶ 두번째 커밋 완료
* 깃에서 특정 파일 제외하고 싶을 때 폴더에 .gitignore 텍스트파일 만들기(확장자X) ▶ e.txt 넣고 저장 ▶ e.txt 파일은 제외됨 .gitignore 텍스트파일에 /aaa 적고 ▶ 폴더에 aaa라는 폴더 만들어서 안에 c.txt d.txt 만들어두면 aaa폴더안의 파일도 제외됨
폴더에 c.txt 파일 만들고 세번째 커밋
3. 버전
- 첫번째 숫자 : 주버전. 크게 다른 경우. - 두번째 숫자 : 부버전. 새로운 기능 추가. - 세번째 숫자 : 수버전. 버그 수정. 커밋 내용 우클릭하고 태그 클릭 ▶ 이름 v0.1.1 넣고 추가
4. 커밋 되돌리기
(1) revert : 기존버전 삭제 안하고 새로운 버전으로 생성 (2) reset : 되돌아가는 버전의 시점으로 되돌아감 - soft : 변경사항 유지 + 커밋 취소 - mixed : 변경사항 유지 + 스테이지, 커밋 취소 - hard : 변경사항 유지안함 (파일 내용도 원상복구)
5. 스태시(stash)
- 임시 저장기능
5. 브랜치
1) 브랜치 나누기
2) 브랜치 병합
- 반드시 master로 체크아웃해야함
- 병합 후 해당 브랜치는 삭제
6. 병합 충돌 해결
병합 후 충돌 알림 ▶ 스테이지에 올라가지 않은 파일 ▶ 클릭 ▶ 우클릭 ▶ 충돌 해결
(스테이지에 올라가지 않은 파일 내용) <<<<<< HEAD master_a ========== foo_a >>>>>> foo
1) 내 것을 이용해 충돌 해결 (=master 현재브랜치)
<<<<<< HEAD 부분 master_a
선택 후 파일상태 탭 ▶ 커밋 내용 안에 내용이 들어가 있음 ▶ 커밋 ▶ 파일 열어보면 master_a로 되어있음
2) 저장소 것을 이용해 충돌 해결 (= foo)
========== 부분 foo_a >>>>>> foo
선택 후 파일상태 탭 ▶ 커밋 내용 안에 내용이 들어가 있음 ▶ 커밋 ▶ 파일 열어보면 foo_a로 되어있음
Server ▶ su - ubuntu 입력 ▶ touch aaa.txt ▶ ls - l로 만들어진 aaa.txt 파일 확인 ▶
server-b ▶ ls -l 하면 aaa.txt파일 확인 가능 ▶ nano aaa.txt 해서 아무거나 입력해서 저장 ▶ exit 입력 (SSH 접속 끄기)
▶ Server ▶ cat aaa.txt ▶ server-b에서 저장한 내용을 확인할 수 있음
2. nslookup
- 네트워크 디버깅을 위해 자주 사용되는 리눅스 명령어 - DNS 서버에 직접 DNS 쿼리를 하고 그 결과를 출력 - DNS 설정이 정상적인지, DNS 서버가 정상적으로 동작하고 있는지, 네트워크가 의도한대로 설정되어있는지 등 확인 - 루트 ▶ nslookup ▶ http://www.naver.com ▶ ip 주소 등 확인 가능
3. 네임서버 설정
- 기본 흐름 : URL 입력 ▶ /etc/host.conf 조회 ▶ /etc/hosts에 있으면 IP 주소로 이동, 없으면 /etc/resolv.conf에 설정된게 있는지 확인한 후 연결
루트 ▶ nano /etc/resolv.conf (DNS 설정파일) ▶ nameserver 127.0.0.53 앞에 # 붙여서 주석처리 ▶ 파이어폭스에서 네이버 접속 ▶ 접속 안되는거 확인 가능 ▶ nano /etc/hosts (호스트 이름이나 도메인 이름을 IP주소로 변환하는 운영체제 파일) ▶ 13.125.33.124http://www.kgitbank.com 입력 ▶ 파이어폭스에서 http://www.kgitbank.com 들어가면 접속 잘 되는거 확인 가능 ▶ /etc/hosts ▶ 163.239.1.47 http://www.kgitbank.com 입력 ▶ 파이어폭스에서 http://www.kgitbank.com 들어가면 서강대학교 홈페이지로 접속됨 /etc/resolv.conf 와 /etc/host.conf 파일 원래대로 해놓기
- Logical Volumn Manager : 논리 하드디스크 관리자 - 여러개의 하드디스크를 한 개의 파티션으로 구성한 후 다시 필요에 따라 나누는 것
--Server 에서 스냅샷 raid6+10 추가 (테스트 예제) 하드디스크 2GB /single, 하드디스크 3GB /single 로 추가한 후 부팅 ▶ ls -l /dev/sd* 장치 확인
fdisk /dev/sdb ▶ Command : n ▶ Select : p ▶ Partition number : 1 ▶ First sector : enter ▶ Last sector : enter ▶ Command : t ▶ Hax code : 8e ▶ Command : p ▶ Command : w
fdisk /dev/sdc ▶ Command : n ▶ Select : p ▶ Partition number : 1 ▶ First sector : enter ▶ Last sector : enter ▶ Command : t ▶ Hax code : 8e ▶ Command : p ▶ Command : w
▶ ls -l /dev/sd* 로 확인 ▶ apt -y install lvm2 설치 ▶ pvcreate /dev/sdb1 ▶ pvcreate /dev/sdc1 ▶ vgcreate myLG /dev/sdb1 /dev/sdc1 (하나로 묶기) ▶ vgdisplay (확인) ▶lvcreate --size 1G --name myLG1 myLG ▶lvcreate --size 3G --name myLG2 myLG ▶lvcreate --extents 100%FREE --name myLG3 myLG ▶ls -l /dev/myLG로 확인 ▶mkfs.ext4 /dev/myLG/myLG1 ▶mkfs.ext4 /dev/myLG/myLG2 ▶mkfs.ext4 /dev/myLG/myLG3 ▶kdir /lvm1 ▶mkdir /lvm2 ▶mkdir /lvm3 ▶mount /dev/myLG/myLG1 /lvm1 ▶mount /dev/myLG/myLG2 /lvm2 ▶ mount /dev/myLG/myLG3 /lvm3 ▶df 로 확인 ▶nano /etc/fstab
▶/dev/myLG/myLG1 /lvm1 ext4 defaults 0 0
/dev/myLG/myLG2 /lvm2 ext4 defaults 0 0
/dev/myLG/myLG3 /lvm3 ext4 defaults 0 0
▶reboot
(테스트 예제) - server-b에 하드디스크 4GB, 5GB 추가하고 LVM으로 3G씩 나누기 ls -l /dev/sd* 장치 확인 fdisk /dev/sdb ▶Command : n ▶Select : p ▶Partition number : 1 ▶First sector : enter ▶Last sector : enter ▶Command : t ▶Hax code : 8e ▶Command : p ▶Command : w
fdisk /dev/sdc ▶Command : n ▶Select : p ▶Partition number : 1 ▶First sector : enter ▶Last sector : enter ▶Command : t ▶Hax code : 8e ▶Command : p ▶Command : w
▶ ls -l /dev/sd* 로 확인 ▶apt -y install lvm2 설치 ▶pvcreate /dev/sdb1 ▶pvcreate /dev/sdc1 ▶vgcreate myLG /dev/sdb1 /dev/sdc1(하나로 묶기) ▶vgdisplay 확인 ▶lvcreate --size 3G --name myLG1 myLG ▶lvcreate --size 3G --name myLG2 myLG ▶lvcreate --extents 100%FREE --name myLG3 myLG ▶ls -l /dev/myLG로 확인 ▶mkfs.ext4 /dev/myLG/myLG1 ▶mkfs.ext4 /dev/myLG/myLG2 ▶mkfs.ext4 /dev/myLG/myLG3 ▶mkdir /lvm1 ▶mkdir /lvm2 ▶mkdir /lvm3 ▶mount /dev/myLG/myLG1 /lvm1 ▶mount /dev/myLG/myLG2 /lvm2 ▶mount /dev/myLG/myLG3 /lvm3 ▶df 로 확인 ▶nano /etc/fstab
(테스트예제) 하드디스크에 사용자 두명에 대한 디스크 설정 하드디스크 10기가 추가 ▶ls -l /dev/sd* 장치 확인 ▶fdisk /dev/sdb ▶Command : n ▶Select : p ▶Partition number : 1 ▶First sector : enter ▶Last sector : enter ▶Command : p ▶Command : w ▶mkfs.ext4 /dev/sdb1 ▶mkdir /userHome ▶mount /dev/sdb1 /userHome ▶df 확인 ▶gedit /edt/fstab ▶/dev/sdb1 /userHome ext4 defaults 0 0 입력 ▶reboot
▶ gedit /etc/fstab ▶ /dev/sdb1 /userHome ext4 defaults,usrjquota=aquota.user,jqfmt=vfsv0 0 0 으로 수정 ▶mount -option remount /userHome (새로 설정한 값으로 마운트) ▶apt -y install quota ▶cd /userHome ▶quotaoff -avug (쿼터를 끄는 작업) ▶quotacheck -augmn (확인) ▶rm -f aquota.* (쿼터 관련 파일 삭제) ▶quotacheck -augmn (확인) ▶touch aquota.user aquota.group (쿼터 관련 파일 생성) ▶chmod 600 aquota.* (권한 부여) ▶qutacheck -augmn (확인) ▶quotaon -avug 쿼터 켜기 (turned on 안되면 reboot)
▶ edquota -u aaa 사용자 aaa 에게 하드디스크 용량 할당하는 에디터 열기) - blocks 부분은 파일 용량 (0이면 무한대) - soft 는 quota까지만 쓸 수 있음 - hard는 limit 까지 쓸 수는 있으나 grace 기간 만큼 quota만큼까지 용량을 정리해야함 - inodes 부분은 파일의 개수 (0이면 무한대)
▶ blocks soft 30720 입력, hard 40960 입력 후 저장 ▶chmod 644 /boot/vmlinuz-6.8.0-38-generic 파일 권한 변경 ▶ su - aaa 계정을 aaa로 사용자 전환 ▶cp /boot/vmlinuz-6.8.0-38-generic test1 (test1이라는 이름으로 위의 파일 복사) cp /boot/vmlinuz-6.8.0-38-generic test2 (test2이라는 이름으로 위의 파일 복사) ▶cp /boot/vmlinuz-6.8.0-38-generic test3 (test3이라는 이름으로 위의 파일 복사) ▶디스크 할당량이 초과되었다는 에러메세지 뜸 ▶ls - l 로 확인해보면 test3 파일이 용량을 다 채우지 못하고 도중에 멈춘걸로 확인됨 ▶quota 치면 확인 가능 ▶exit ▶ repquota /userHome 입력하면 사용자별로 용량 설정 확인 가능
3. 쉘
1) 환경변수
gedit name.sh ▶ #!/bin/sh echo "사용자 이름 : " $USER echo "홈 디렉토리 : " $HOME exit 0 ▶ ls -l 해보면 name.sh 파일을 확인해보면 읽고 쓰고는 되는데 실행하는 권한이 없음 ▶ chmod +x name.sh
nano var1.sh ▶ #!/bin/sh myvar="Hi linux" echo $myvar echo "$myvar" echo '$myvar' echo \$myvar echo 값 입력 : read myvar echo '$myvar = '$myvar exit 0 ▶ sh var1.sh(실행) ▶ Hi linux Hi linux $myvar $myvar 값 입력 : linux $myvar = linux
3) 연산
nano var2.sh ▶ #!/bin/sh num1=100 num2=$num1+200 echo $num2 exit 0 ▶ sh var2.sh ▶ 100+200 으로 출력
#!/bin/sh num1=100 num2=$num1+200 echo $num2 num3=`expr $num1 + 200` echo $num3 exit 0 ▶ 100+200 <br> 300 으로 출력 ▶ 연산을 하기 위해서는 수식을 ``로 묶어야함
1) 원본파일 mk dir linktest 입력 ▶ cd linktest 입력 ▶ nano basefile 입력 ▶ 내용 입력 후 저장 ▶ cat basefile 하면 입력된 내용 확인 가능 ▶ ls -il 입력 하면 1051219 -rw-r--r-- 1 root root 45 7월 22 09:17 basefile 이렇게 뜨는데 맨 앞 숫자가 링크노드
2) 하드링크 : 파일이 만들어짐 ln basefile hardlink 입력 ▶ ls -il하면 1051219 -rw-r--r-- 2 root root 45 7월 22 09:17 basefile 1051219 -rw-r--r-- 2 root root 45 7월 22 09:17 hardlink 이렇게 나오는데 링크노드가 같음을 확인할 수 있음
3) 소프트링크 : 바로가기가 만들어짐
ln -s basefile softlink 입력 ▶ ls -il하면 1051219 -rw-r--r-- 2 root root 45 7월 22 09:17 basefile 1051219 -rw-r--r-- 2 root root 45 7월 22 09:17 hardlink 1051218 lrwxrwxrwx 1 root root 8 7월 22 09:19 softlink -> basefile 이렇게 나오는데 링크노드는 다르지만 basefile을 가리키고 있음을 알 수 있음
mv basefile ../ 입력해서 베이스 파일을 루트로 옮기고 ls 하면 하드링크와 소프트링크만 나옴 ▶ ls -il 하면 1051219 -rw-r--r-- 2 root root 45 7월 22 09:17 hardlink 1051218 lrwxrwxrwx 1 root root 8 7월 22 09:19 softlink -> basefile 이렇게 나오고 베이스파일이 없음을 확인할 수 있음 cat softlink 하면 디렉터리 찾을수 없다고 나옴
mv ../basefile . 입력해서 다시 베이스 파일을 현재 파일로 이동 ▶ ls 하면 베이스파일, 하드링크, 소프트링크 다 나옴 ▶ cat softlink 해도 잘 나옴
2. 파일설치
1) dpkg (설치파일 자체) - 설치 : dpkg -i 패키지이름 - 삭제 : dpkg -r 패키지이름 - 조회 : dpkg -l 패키지이름 - deb 파일 내용 조회 - 리눅스의 설치파일은 확장자 deb, 패키지라 부름. - dekg --info 패키지이름.deb
(테스트예제)
http://kr.archive.ubuntu.com/ubuntu/pool/universe/g/galculator/ 파이어폭스에서 접속
▶ galculator_2.1.4-1.2build2_amd64.deb 파일 다운로드
http://kr.archive.ubuntu.com/ubuntu/pool/universe/a/axel/ 파이어폭스에서 접속
2) apt (설치링크-인터넷) - dpkg 명령어의 패키지 의존성 문제를 완전히 해결한 명령어 - dpkg는 의존성이 있는 다른 패키지를 먼저 설치하고 해당 패키지를 설치해야함 - apt는 우분투가 제공하는 저장소에서 해당 파일과 의존성 있는 다른 deb파일까지 다운로드한 후 자동으로 설치 - dpkg 명령을 사용하기 위해서는 패키지를 미리 다운로드 해야하지만, apt는 미리 다운로드 할 필요가 없음 - 단점은 인터넷이 반드시 연결되어 있어야함 - 우분투 저장소 위치 : /etc/apt/sources.list - apt -y install 패키지 이름 (선택이 필요한 상황에서 다 yes처리하며 설치) - 패키지 목록 업데이트 : apt update - apt remove 패키지이름 : 기존에 설치된 패키지 삭제 - apt purge 패키지이름 : 기존에 설치된 패키지를 설정파일 포함해서 완전히 제거 - apt autoremove : 사용하지 않는 패키지 모두 제거 - apt clean : 내려받은 파일 제거 - apt autoclean : 내려받은 파일 제거 - apt-cache show 패키지 이름 : 패키지 정보 보기 - apt-cache depends 패키지 이름 : 패키지 의존성 확인 - apt-cache rdepends 패키지 이름 : 이 패키지에 의존하는 다른 패키지 목록 확인
(테스트 예제) 루트 ▶ apt-cache show galculator 입력하면 galculator 정보 확인 루트 ▶ apt-cache depends galculator 입력하면 galculator 에 대한 의존성 확인 루트 ▶ apt install galculator 입력 > galculator 설치
(sources.list) - main : 우분투에서 공식적으로 지원하는 무료 소프트웨어 - universe : 우분투에서 지원하지 않는 무료 소프트웨어 - multiverse : 우분투에서 공식적으로 지원하는 유료 소프트웨어 - restricted : 우분투에서 지원하지 않는 유료 소프트웨어
3. 파일 압축과 묶기
1) 압축 - xz, bz2, gz, zip, Z - gz가 예전에 많이 사용, xz나 bz2가 요즘은 많이 사용
① xz : 확장명 xz로 압축하거나 풀어줄 때 사용 - xz 파일이름 : 파일이름.xz로 압축, 기존 파일 삭제 - xz -k 파일이름 : 파일이름.xz로 압축, 기존 파일 삭제 안함 - xz -d 파일이름.xz : 압축 풀기 - xz -l 파일이름.xz : 압축파일에 포함된 파일이름과 압축률 등 정보 출력
② bzip2 : 확장명 bz2로 압축하거나 풀어줄 때 사용 - bzip2 파일이름 : 파일이름.bz2로 압축 - bzip2 -k 파일이름 : 파일이름.bz2로 압축, 기존 파일 삭제 안함 - bzip2 -d 파일이름.bz2 : 압축 풀기
③ gzip : 확장명 gz로 압축하거나 풀어줄 때 사용 - gzip 파일이름 : 파일이름.gz로 압축 - gzip -d 파일이름.gz : 압축 풀기
④ zip/unzip : windows와 호환되는 확장명.zip으로 압축하거나 풀어줄때 사용 - zip 새로생성될파일이름.zip - unzip 압축파일이름.zip - 거의 사용 안함
2) 파일묶기 - 리눅스는 파일압축과 묶기가 별개의 프로그램으로 실행됨 - 묶기 명령 : tar - 묶인 파일의 확장자 : .tar [동작] - c : 새로운 묶음을 만들 때 - x : 묶은 파일을 풀 때 - t : 묶음을 풀기전에 묶인 경로를 보여줌 - c : 묶음을 풀 때 지정된 디렉터리에 풀어줌. 지정하지 않으면 묶을때와 동일한 디렉토리에 풀음 [옵션] - f : 필수, 묶음 파일 이름 지정 - v : visual. 파일을 묶거나 푸는 과정을 보여줌 - J : tar + xz - z : tar + gzip - j : tar + bzip2
(테스트 예제) 루트 ▶ tar cvf my.tar /etc/systemd/ 입력 ▶ 묶기 루트 ▶ tar tvf my.tar 입력 ▶ my.tar의 경로 보기 루트 ▶ tar cvfJ my.tar.xz /etc/systemd/ 입력 ▶ tar_gzip 묶기 루트 ▶ ls -l 입력 ▶ 압축파일 확인 가능 루트 ▶ tar cvfz my.tar.gz /etc/systemd/ 입력 루트 ▶ mkdir newdir 입력 ▶ tar Cxvf newdir my.tar 입력 ▶ newdir에 압축 풀어짐 ▶ cd newdir 입력
▶ ls 눌러서 etc폴더 확인 ▶ cd etc 입력 ▶ ls -l입력 ▶ systemd 파일 확인 ▶ cd systemd 입력
▶ ls -l 입력해서 압축해제된 파일들 확인
4. 파일 찾기 - find/which/whereis/location
루트 ▶ find /etc -name "*.conf" 입력하면 이름이 .conf로 끝나는 파일 찾기 루트 ▶ find /home -user ubuntu 입력하면 홈 디렉터리 안에 우분투 사용자가 가진 파일을 찾기 루트 ▶ find ~ -perm 644 입력하면 현재 사용자의 홈디렉터리에서 권한이 644에 해당되는 파일 찾기 루트 ▶ find /usr/bin -size 10k -size + 1 입력하면 bin 폴더에서 사이즈가 해당 범위내에 있는 파일 찾기 루트 ▶ find /home -name "*.swp" 입력하면 파일찾기
루트 ▶ find /home -name "*.swp" -exec rm{} \; 입력하면 파일을 찾아서 실행까지함 루트 ▶ which gzip 입력하면 gzip의 경로를 알려줌 루트 ▶ whereis gzip 입력하면 gzip의 경로, 정보 등을 다 알려줌 루트 ▶ apt install location 입력해서 설치 > 루트 > location gzip 입력하면 경로, 설명들이 상세하게 나옴
5. 예약작업
1) cron : 주기적으로 반복되는 일을 자동으로 실행할 수 있도록 시스템 작업을 예약해놓는 것 루트 ▶ nano /etc/crontab 입력 ▶ 기본적인 설명 나옴 # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) # | | | | | # * * * * * user-name command to be executed
루트 ▶ systemctl status cron 입력 ▶ 크론의 동작상태 알 수 있음 루트 ▶ apt install gedit 입력 후 설치 ▶ gedit /etc/crontab 입력 ▶ 11번째 이하로 다 지우기
▶ 01 03 15 * * root /root/myBackup.sh 입력 ▶ 저장 ▶ touch myBackup.sh 입력 ▶ chmod 755 myBackup.sh 입력
▶ gedit myBackup.sh 입력 ▶ 루트 ▶ mkdir backup 입력 ▶ 루트
▶ systemctl restart cron 입력해서 내가 에디터로 수정한 크론내용으로 적용
2) at : 일정한 시점에 한번만 실행되고 소멸 at 3:00am tomorrow at 11:00pm January 30 at now + 1 hours
루트 ▶ apt -y install rdate at 입력 후 설치 ▶ at 4:00 am tomorrow 작동할 시간 입력 ▶ apt -y upgrade 입력
▶ reboot 입력 ▶ Ctrl D 눌러서 빠져나가기 ▶ 루트 ▶ at -l 입력해서 만들어진 작업 확인
▶ atrm 1 입력 하면 저장했던 at 1번 작업 삭제됨 ▶ at -l 입력해서 삭제된거 확인
6. 네트워크
- TCP - UDP - IP주소 - 호스트 이름 - 도메인 이름 - 네트워크 주소 - 넷마스크 11111111 11111111 111111111 10000000 255 255 255 128 >> 192.168.128.0 ~ 192.168.128.127 >> 192.168.128.128 ~ 192.168.128.255 - 브로드캐스트 주소 : 내부 네트워크의 모든 컴퓨터가 수신하는 주소(마지막 ip주소값) - 게이트웨이 : 내부에서 밖으로 나갈때 연결하기 위한 컴퓨터 또는 장비 - DNS 서버 : 도메인 주소를 IP 주소로 변환해주는 서버 컴퓨터 - ifconfig ens32 : ens32의 네트워크 설정 정보를 출력 - ifdown ens32 : ens32의 네트워크 장치를 중지 - ifup ens32 : ens32의 네트워크 장치를 가동 - nm-connection-edit, nmtui(Network Manager Text User Interface) : 네트워크 설정 변경하는 명령어 - systemctl <start/stop/restart/status> networking - ping 도메인주소/IP주소 : 해당 주소와 통신을 주고 받아 네트워크 연결이 되어있는지 확인
server-b ▶ root/password입력 ▶ ls /etc/netplan/*.yaml 입력 ▶ nano /etc/netplan/50-cloud-init.yaml 입력 ▶ 수동으로 변환하고 싶은경우 아래와 같이 입력 후 저장 end32: dhcp4 : no addresses : [ip주소/24] gateway4: 게이트웨이 주소 nameserves : address : [8.8.8.8]
7. 기타 명령어
- grep : 특정 단어 필터 ps -ef | grep bash : bash가 들어간 목록 보기 - > ls -l > list.txt : list.txt에다가 ls -l의 결과를 담아주기. 기존 내용에 덮어쓰기. - >> ls -l >> list.txt : list.txt에다가 ls -l의 결과를 담아주기. 기존 내용 아래에 붙여쓰기. - sort sort < list.txt > out.txt : list.txt의 sort 결과를 out.txt에 담기 - 서비스 실행/중지/재실행 cd /lib/systemd/system 입력 ▶ ls *.service 입력 ▶ systemctl start/stop/restart 서비스 이름
8. 하드디스크 추가
서버 ▶ Edit virtual machine settings ▶ Hard Disk ▶ Advanced... 클릭 ▶ 하드디스크 스카시 장비 현황 볼 수 있음 ▶ 다시 돌아와서 Add버튼 클릭 ▶ 하드디스크 ▶ SCSI ▶ Create a new virtual disk ▶ 1GB, 맨 밑에 Split virtual disk into multiple files만 체크 ▶ 다만들고 다시 Advanced 들어가보면 0번 슬롯 1번째로 잡힌것을 확인할 수 있음
루트 ▶ ls -l /dev/sd* 입력 ▶ 장치 추가된거 (sdb) 확인 가능
루트 ▶ fdisk /dev/sdb 입력 ▶ n (신규파티션추가) ▶ p (primary /extened (리눅스 파이션 설정)) ▶ 1 (파티션 숫자설정 1~4) ▶ 엔터(용량설정(default Enter)) ▶ 엔터(용량설정(default Enter))▶ p(파티션 설정보기) ▶ w(파티션 설정 저장) 입력
Device Boot Start End Sectors Size Id Type /dev/sdb1 2048 2097151 2095104 1023M 83 Linux 이렇게 하드디스크 설정이 된것을 알 수 있음 ls -l /dev/sd* 하면 sdb1이 생김
루트 ▶ mkfs.ext4 /dev/sdb1 입력 ▶ 루트 ▶ mkdir /mydata 입력 ▶ cp /boot/vmlinuz-6.8.0-38-generic /mydata/test1 앞의 파일을 뒤에 폴더에 test1이름으로 복사 ▶ ls -l /mydata 입력하면 복사된 파일 확인 가능 ▶ mount /dev/sdb1 /mydata 입력 ▶ ls -l /mydata 입력하면 마이데이터 안에 파일이 생긴것을 확인할 수 있음 (마운트 되었다는 의미)
루트 ▶ umount /dev/sdb1 입력 ▶ ls -l /mydata 입력 하면 언마운트 되어 기존파일인 test1만 보여짐(계속 저장되지 않음)
루트 ▶ mount /dev/sdb1 /mydata 입력해서 다시 마운트 ▶ gedit /etc/fstab 입력 ▶ 에디터 맨 밑 12번째 행에 입력 /dev/sdb1 /mydata ext4 defaults 0 0 ▶ 저장 ▶ reboot ▶ ls -l /mydata 입력하면 test2도 확인가능
9. RAID 방식 : 여러개의 하드디스크를 하나처럼 사용하기
- 하드웨어 방식 - 소프트웨어 방식 : 운영체제에서 지원하는 방식. 저렴하게 데이터를 저장하고 관리 - RAID - 0 : 스트라이핑 (최소 2개) - RAID - 1 : 미러링 (최소 2개) - RAID - 2 : bit 단위 스트라이핑, error correction을 위해 Hamming code 를 사용 (최소 3개), 현재 사용 X - RAID - 3 : Byte 단위 스트라이핑, error correction을 위해 패리티 디스크를 1개 사용, 현재 사용 X - RAID - 4 : Block 단위 스트라이핑, error correction을 위해 패리티 디스크를 1개 사용, 현재 사용 X - RAID - 5 : Block 단위 스트라이핑, error correction을 위해 패리티를 1개의 디스크에 저장,
패리티 저장을 매번 다른 디스크에 저장. 가장 많이 사용 (최소 3개)
- RAID - 6 : RAID 5에서 성능, 용량을 좀 더 줄이고, 안정성을 좀 더 높인 RAID Level
Block 단위 스트라이핑, error correction을 위해 패리티를 2개의 디스크에 저장,
패리티 저장을 매 번 다른 디스크에 저장. (최소 4개)
ls -l /dev/sd* ▶ fdisk /dev/sdb ▶ n (신규파티션추가) ▶ p (primary /extened (리눅스 파이션 설정)) ▶ 1 (파티션 숫자설정 1~4) ▶엔터 ▶엔터 ▶t(파티션 종류 변경 (82 - 스왑 파티션 / 83 - 리눅스 파티션 / b - W95 FAT32) )▶ fd ▶ p(파티션 설정보기) ▶ w(파티션 설정 저장) ▶apt -y install mdadm▶ halt -p ▶스냅샷 추가 하드디스크 4개 추가
(테스트 예제) -- b와 c연결 (RAID-0) fdisk -l /dev/sdb (상태 확인) ▶ fdisk -l /dev/sdc (상태 확인) ▶mdadm --create /dev/md0 --level=0 --raid-devices=2 /dev/sdb1 /dev/sdc1(뒤의 sdb1, sdc1 두개의 장치를 raid-0 으로 변환해서 md0으로 지정) ▶mdadm --detail --scan (상태 확인) ▶mkfs.ext4 /dev/md0 (md0을 포맷) ▶ mkdir /raid0 (디렉터리 생성) ▶mount /dev/md0 /raid0 (md0을 마운트하고 raid0으로 명칭 지정) ▶df (현황 확인) ▶ gedit /etc/fstab (장비 마운트 저장) ▶/dev/md0 raid0 ext4 defaults 0 0 입력 후 저장 ▶mdadm --detail --scan 입력해서 나오는 데이터 복사(ARRAY /dev/md/Server:0 metadata=1.2 UUID=23f739ea:58e6c287:54c26f82:c41ae7df) ▶gedit /etc/mdadm/mdadm.conf 맨 아래에 붙여넣기하고 저장 ▶ update-initramfs -u (업데이트) ▶ reboot
(테스트 예제) -- d와 e연결 (RAID-1)
fdisk -l /dev/sdd ▶ fdisk -l /dev/sde▶ mdadm --create /dev/md1 --level=1 --raid-devices=2 /dev/sdd1 /dev/sde1 ▶y ▶mdadm -- detail --scan ▶mkdir /raid1 ▶mkfs.ext4 /dev/md1 ▶mount /dev/md1 /raid1 ▶df ▶ gedit /etc/fstab ▶/dev/md1 raid1 ext4 defaults 0 0 입력 후 저장 ▶mdadm --detail --scan 입력해서 나오는 데이터 복사
▶gedit /etc/mdadm/mdadm.conf 맨 아래에 붙여넣기하고 저장 ▶update-initramfs -u ▶ reboot
(테스트 예제) -- f, g, h 연결 (RAID-5)
fdisk -l /dev/sdf▶ fdisk -l /dev/sdg ▶ fdisk -l /dev/sdh ▶ mdadm --create /dev/md5 --level=5 --raid-devices=3 /dev/sdf1 /dev/sdg1 /dev/sdh1 ▶y▶mdadm -- detail --scan▶mkdir/raid5▶mkfs.ext4 /dev/md5▶mount /dev/md5 /raid5▶df▶gedit /etc/fstab▶/dev/md5 raid5 ext4 defaults 0 0 입력 후 저장▶mdadm --detail --scan 입력해서 나오는 데이터 복사 ▶gedit /etc/mdadm/mdadm.conf 맨 아래에 붙여넣기하고 저장▶update-initramfs -u▶reboot
---- 초기설정으로 스냅샷 이동
용량 1기가로 8대 만들기 ls -l /dev/sd* 로 확인
(테스트 예제) -- b, c, d, e 연결 (RAID-6)
fdisk /dev/sdb ▶n ▶p ▶1 ▶ enter ▶enter ▶t ▶fd ▶p ▶w 같은 방식으로 sdc, sdd, sde도 설정 ▶ls -l /dev/sd* 로 확인 ▶apt -y install mdadm 설치 ▶mdadm --create /dev/md6 --level=6 --raid-devices=4 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1 ▶mdadm --detail /dev/md6 로 장치 4개 물린거 확인 ▶ mkfs.ext4 /dev/md6 포맷 ▶mkdir /raid6 ▶ mount /dev/md6 /raid6 ▶df로 확인 ▶gedit /etc/fstab 열어서 맨아래에 /dev/md6 /raid6 ext4 defaults 0 0 입력 후 저장 ▶mdadm --detail --scan 내용 복사 ARRAY /dev/md6 metadata=1.2 UUID=bf8f953c:c1ee2335:ef71bb42:742e9dd0 ▶gedit /etc/mdadm/mdadm.conf 맨밑에 붙여넣기 ▶update-initramfs -u ▶reboot
1. 제어판 > 프로그램기능 > VMware Workstation이 이미 설치되어있으면 삭제
2. ubuntu-24.04-desktop-amd64. iso파일, VMware 파일 설치
1) VMware-workstation-full-17.5.2-23775571.exe 설치
2) 워크스페이스 > linux폴더 > Server폴더 생성
3) VMware에서 File > New Virtual Machine > Typical 설치
> Linux Ubuntu64-bit 선택 > virtual machine name : Server, Location : D:\fintechkmy\linux\Server
> Vmware 왼쪽에서 설정된 서버의 사양을 확인할 수 있음
4) Edit virtual machine settings 에서 서버 사양 변경 가능함 - Memory 4GB - Processors : Number of processors 1개로 변경 - Harddisk : 기존 20GB 하드디스크 Remove > Add > Hard Disk > SCSI > Create a new virtual disk
> 용량 80GB로 변경 > 원래는 Split하지만 수업의 편의를 위해 Store virtual disk as a single file 선택
> Finish - SoundCard : Remove - USB : Remove >> 최종적으로 Memory 4GB, Processor 1, Hard Disk 80GB, CD/DVD, Network Adapter NAT, Display 만 있으면 됨
5) CD/DVD 선택 > Connect at power on > ubuntu-24.04-desktop-amd64 파일 선택 후 OK > 시작 > 마우스 클릭
> install 엔터 > 언어 한국어 > 키보드 유형 "한국어"로 설정 > 유선 연결 사용 > Update now 버튼 클릭 안함
> Ubuntu 설치 > Interactive installation > Default selection
> 그래픽과 Wi-Fi 하드웨어를 위한 서드파티 소프트웨어 설치, 추가 미디어 포맷 지원을 내려받아 설치 둘다 체크
> 수동 파티셔닝 > 남은 공간 선택 후 +버튼 클릭 > 크기 4096 MB, 용도 Swap > 남은 공간 선택 후 +버튼 클릭
> 크기 남은 크기 전체, 용도 Ext4, 마운트 위치 / > 계정 이름 ubuntu, 컴퓨터 이름 Server, 암호 ubuntu > 설치 완료
> 사용자 로그인 > skip for now > 공유 안함 > Finish
* 컨트롤 알트키 누르면 마우스 다시 나타남
6) 루트 세팅 : 바탕화면 > 우클릭 > 터미널로 열기 > sudo su - root 입력 > 암호 ubuntu 입력 > passwd 입력
> 신규 비밀번호로 password 입력 * root는 # 표시, 사용자는 $ 표시
7) 바탕화면 우측 위 아이콘 우클릭 > 환경설정 톱니바퀴 아이콘 클릭 > 왼쪽 메뉴바 시스템 클릭 > 사용자 클릭
> 상단 잠금해제 클릭 > 암호 입력 ubuntu > 자동 로그인 켜기
8) 터미널 > nano /etc/gdm3/custom.conf 입력 > [daemon] 나오면 AutomaticLogin = ubuntu 를 root로 바꾸기
> [security] 아래에 AllowRoot=True 적기 > Ctrl+X 누르고 Y눌러서 저장하고 엔터
9) 터미널 > nano /etc/pam.d/gdm-password > 3번행 주석 처리(#)
10) 터미널 > nano /etc/pam.d/gdm-autologin > 3번행 주석 처리(#)
11) 재부팅 reboot
12) 왼쪽 앱 표시 아이콘 클릭 > 파란색 소프트웨어 및 업데이트 클릭 > 업데이트 > 자동으로 업데이트 확인 : 하지 않기
> 새 우분투 버전 알려주기 : 하지 않기
13) 우측 위 설정 > 네트워크 > 유선 환경설정 아이콘 클릭 > IPv4 탭 > IPv4 방식 : 수동
> 주소 : 192.168.111.100 입력, 네트마스크 : 255.255.255.0, 게이트 웨이 : 192.168.111.2,
네임서버 : 192.168.111.2 입력 > 적용
14) 터미널 > cd /etc/apt 입력 > ls 입력 > mv sources.list sources.list.bak 입력 > ls 입력
2. STS에서 File > new > Spring legacy project > Spring MVC Project > 프로젝트명 : com.kgitbank.프로젝트명(mavenStudent) > mavenStudent 우클릭 > Run as > Run on Server > Next > htto_content.xml 화면이 나오면 설치 완료
<?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="com.itbank.mavenBoard.dto.boardMapper">
<select id="listBoard" resultType="boardDTO"><!-- configuration.xml에서 alias 줬기 때문에 student.dto.StudentDTO 안써도됨 -->
select * from board order by num desc
</select>
</mapper>
@RequestMapping(value="/update.do", method=RequestMethod.POST)
public String updateProBoard(@ModelAttribute BoardDTO dto, BindingResult result) { // 예측가능한(null 세팅) 에러가 날 것 같으면 미리 처리해둘 수 있음. 에러가 나면 BindingResult에 담아두겠다.
if(result.hasErrors()) { // dto객체를 만드는 중 에러가 난다면
dto.setNum(0); // 0으로 세팅한다. 내가 알아서 해결하는 코드
}
int res = boardMapper.updateBoard(dto);
return "redirect:list_board.do";
}
boardMapper.xml
<update id="updateBoard" parameterType="boardDTO">
update board set subject=#{subject}, email=#{email}, content=#{content} where num=#{num}
</update>
// 게시글 삭제 폼 (delete.do - GET)
BoardController.java
@RequestMapping(value="/delete.do", method=RequestMethod.GET)
public String deleteFormBoard() {
return "board/deleteForm";
}
@RequestMapping(value="/delete.do", method=RequestMethod.POST)
public String deleteProBoard(@RequestParam Map<String, String> params) {
BoardDTO dto = boardMapper.getBoard(Integer.parseInt(params.get("num")));
if (dto.getPasswd().equals(params.get("passwd"))) {
int res = boardMapper.deleteBoard(Integer.parseInt(params.get("num")));
}
return "redirect:list_board.do";
}
boardMapper.xml
<delete id="deleteBoard" parameterType="int">
delete from board where num = #{num}
</delete>
// 답변형 게시판에 사용
boardMapper.xml
<select id="plusReadcount" parameterType="int">
update board set readcount = readcount + 1 where num = #{num}
</select>
<select id="getCount" resultType="Integer">
select count(*) from board
</select>
<!-- 페이징 -->
<select id="listBoard2" resultType="boardDTO" parameterType="java.util.Map">
<!-- start, end값을 Map으로 받기 -->
select * from (select rownum rn, A.* from
(select * from board order by re_step asc)A)
where rn between #{start} and #{end}
</select>
@RequestMapping(value="/member_update.do", method=RequestMethod.POST)
public String UpdateOkMember(HttpServletRequest req, @ModelAttribute MemberDTO dto) {
int res = MemberMapper.updateMember(dto);
if(res>0) {
req.setAttribute("msg", "회원 수정 성공! 회원 목록 페이지로 이동합니다.");
req.setAttribute("url", "memberAll.do");
return "forward:message.jsp";
} else {
req.setAttribute("msg", "회원 수정 실패! 회원 목록 페이지로 이동합니다.");
req.setAttribute("url", "memberAll.do");
return "forward:message.jsp";
}
}
// 로그인 폼 (login.do - GET)
MemberController.java
@RequestMapping(value="/login.do", method=RequestMethod.GET)
public String LoginMember() {
return "login";
}
1. lib : mybatis-3.2.3.jar 2. db.properties 파일 생성 → DB 속성 3. configuration.xml 생성 → db.properties 파일을 가지고 DB 환경설정 4. studentMapper.xml → 쿼리문을 id로 분류해서 모아둔 곳 5. studentMapper.java → 쿼리문이 실행될 수 있게 메서드 형태로 모아둔 곳 6. StudentController.java (또는 Servlet) → 주소값에 맞춰 실행될 메서드를 정의
1. 학생관리
configuration.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 아래 environments에서 사용할 DB정보가 여기에 저장되어있음(New>General>File) -->
<properties resource="student/mybatis/db.properties"/>
<!-- DTO 별칭 지정 -->
<typeAliases>
<typeAlias type="student.dto.StudentDTO" alias="studentDTO"/>
</typeAliases>
<!-- 공통부분 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 실제 쿼리문이 위치하는 곳 : mapper -->
<mappers>
<mapper resource="student/mybatis/studentMapper.xml"/>
</mappers>
</configuration>
studentMapper.xml
<?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="student.mybatis.studentMapper">
<select id="listStudent" resultType="studentDTO">
<!-- configuration.xml에서 alias 줬기 때문에 student.dto.StudentDTO 안써도됨 -->
select * from student
</select>
<select id="findStudent" parameterType="String" resultType="studentDTO">
select * from student where cname = #{cname}
</select>
<insert id="insertStudent" parameterType="studentDTO">
<!-- int형의 resultType은 별도로 지정안해줘도됨. 알아서 1, 0으로 반환함 -->
insert into student values(#{id}, #{name}, #{cname})
</insert>
<delete id="deleteStudent" parameterType="String">
delete from student where id = #{id}
</delete>
</mapper>
StudentMapper.java
package student.mybatis;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import student.dto.StudentDTO;
public class StudentMapper {
private static SqlSessionFactory sqlSessionFactory;
// SqlSessionFactory 객체 만들기
static {
try {
String resource = "configuration.xml"; // src폴더 안에 있음
Reader reader = Resources.getResourceAsReader(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}catch(IOException e) {
throw new RuntimeException("configuration 인스턴스 생성 중 오류 발생!" + e.getMessage(), e);
}
}
// opensession 메소드를 통해 쿼리문 실행
public static List<StudentDTO> listStudent(){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
List<StudentDTO> list = sqlSession.selectList("listStudent");
return list;
}finally {
sqlSession.close();
}
}
public static int insertStudent(StudentDTO dto) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
int res = sqlSession.insert("insertStudent", dto);
sqlSession.commit(); // insert, delete, update는 DB에 영향 주므로 commit 필수
return res;
} finally {
sqlSession.close();
}
}
public static int deleteStudent(String id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
int res = sqlSession.delete("deleteStudent", id);
sqlSession.commit();
return res;
} finally {
sqlSession.close();
}
}
public static List<StudentDTO> findStudent(String cname){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
List<StudentDTO> find = sqlSession.selectList("findStudent", cname);
//하나만 반환하는 거면 sqlSession.selectOne()
return find;
} finally {
sqlSession.close();
}
}
}
StudentServlet.java
package student;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import student.dao.StudentDAO;
import student.dto.StudentDTO;
import student.mybatis.StudentMapper;
@Controller // annotation
public class StudentServlet {
// StudentDAO 주입
// @Autowired // springStudent-servlet.xml에 등록되어있는 여러 빈 중에 자동으로 가져와짐
// private StudentDAO studentDAO;
// 메서드
@RequestMapping("/student.do")
public String index() {
return "student";
}
@RequestMapping("/insert_student.do")
public String insertStudent(StudentDTO dto) { // @ModelAttribute가 생략되어있어서 알아서 값을 세팅해줌
//int res = studentDAO.insertStudent(dto);
int res = StudentMapper.insertStudent(dto);
return "redirect:list_student.do";
}
@RequestMapping("/list_student.do")
public String listStudent(HttpServletRequest req) { // 매개변수에 req 써주면
//List<StudentDTO> list = studentDAO.listStudent();
List<StudentDTO> list = StudentMapper.listStudent();
req.setAttribute("listStudent", list);
return "list";
}
@RequestMapping("/delete_student.do")
public String deleteStudent(@RequestParam String id) { // @Requestparam 생략되어있음. Reqest중에 id라는 parameter가 있는데 넣어줘
//int res = studentDAO.deleteStudent(id);
int res = StudentMapper.deleteStudent(id);
return "redirect:list_student.do";
}
@RequestMapping("/find_student.do")
public String findStudent(HttpServletRequest req, String cname) {
//List<StudentDTO> list = studentDAO.findStudent(cname);
List<StudentDTO> list = StudentMapper.findStudent(cname);
req.setAttribute("listStudent", list);
return "list";
}
}
2. 게시판 관리
configuration.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 아래 environments에서 사용할 DB정보가 여기에 저장되어있음(New>General>File) -->
<properties resource="board/mybatis/db.properties"/>
<!-- DTO 별칭 지정 -->
<typeAliases>
<typeAlias type="board.dto.BoardDTO" alias="boardDTO"/>
</typeAliases>
<!-- 공통부분 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 실제 쿼리문이 위치하는 곳 : mapper -->
<mappers>
<mapper resource="board/mybatis/boardMapper.xml"/>
</mappers>
</configuration>
boardMapper.xml
<?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="board.mybatis.boardMapper">
<select id="listBoard" resultType="boardDTO"><!-- configuration.xml에서 alias 줬기 때문에 student.dto.StudentDTO 안써도됨 -->
select * from board1 order by num desc
</select>
<insert id="insertBoard" parameterType="boardDTO">
<!-- int형의 resultType은 별도로 지정안해줘도됨. 알아서 1, 0으로 반환함 -->
insert into board1 values(board1_seq.nextval, #{writer}, #{email}, #{subject}, #{passwd}, sysdate, 0, #{content},#{ip})
</insert>
<select id="getBoard" parameterType="int" resultType="boardDTO">
select * from board1 where num = #{num}
</select>
<select id="plusReadcount" parameterType="int">
update board1 set readcount = readcount + 1 where num = #{num}
</select>
<delete id="deleteBoard" parameterType="int">
delete from board1 where num = #{num}
</delete>
<update id="updateBoard" parameterType="boardDTO">
update board1 set subject=#{subject}, email=#{email}, content=#{content} where num=#{num}
</update>
</mapper>
BoardMapper.java
package board.mybatis;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import board.dto.BoardDTO;
public class BoardMapper {
private static SqlSessionFactory sqlSessionFactory;
// SqlSessionFactory 객체 만들기
static {
try {
String resource = "configuration.xml"; // src폴더 안에 있음
Reader reader = Resources.getResourceAsReader(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}catch(IOException e) {
throw new RuntimeException("configuration 인스턴스 생성 중 오류 발생!" + e.getMessage(), e);
}
}
// opensession 메소드를 통해 쿼리문 실행
public static List<BoardDTO> listBoard(){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
List<BoardDTO> list = sqlSession.selectList("listBoard");
return list;
}finally{
sqlSession.close();
}
}
public static int insertBoard(BoardDTO dto) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
int res = sqlSession.insert("insertBoard", dto);
sqlSession.commit(); // insert, delete, update는 DB에 영향 주므로 commit 필수
return res;
} finally {
sqlSession.close();
}
}
public static BoardDTO getBoard(int num){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
BoardDTO dto = sqlSession.selectOne("getBoard", num);
return dto;
}finally {
sqlSession.close();
}
}
public static int plusReadcount(int num) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
int res = sqlSession.update("plusReadcount", num);
sqlSession.commit();
return res;
}finally {
sqlSession.close();
}
}
public static int deleteBoard(int num) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
int res = sqlSession.delete("deleteBoard", num);
sqlSession.commit();
return res;
}finally {
sqlSession.close();
}
}
public static int updateBoard(BoardDTO dto) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
int res = sqlSession.update("updateBoard", dto);
sqlSession.commit(); // insert, delete, update는 DB에 영향 주므로 commit 필수
return res;
} finally {
sqlSession.close();
}
}
}
BoardController.java
package board;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import board.dao.BoardDAO;
import board.dto.BoardDTO;
import board.mybatis.BoardMapper;
@Controller // annotation
public class BoardController {
// DB : BoardDAO 주입
// @Autowired // springBoard-servlet.xml에 등록되어있는 여러 빈 중에 자동으로 가져와짐
// private BoardDAO boardDAO;
// 메서드
@RequestMapping("/list_board.do")
public String listBoard(HttpServletRequest req) {
//List<BoardDTO> list = boardDAO.listBoard();
List<BoardDTO> list = BoardMapper.listBoard();
req.setAttribute("listBoard", list);
return "list";
}
@RequestMapping(value="/write_board.do", method=RequestMethod.GET)
public String wirteFormBoard() {
return "writeForm";
}
@RequestMapping(value="/write_board.do", method=RequestMethod.POST)
public String wirteProBoard(HttpServletRequest req, BoardDTO dto) {
dto.setIp(req.getRemoteAddr()); // IP주소 세팅
//int res = boardDAO.insertBoard(dto);
int res = BoardMapper.insertBoard(dto);
return "redirect:list_board.do";
}
@RequestMapping("/content.do")
public String contentBoard(HttpServletRequest req, int num) {
//BoardDTO dto = boardDAO.getBoard(num, "content");
int res = BoardMapper.plusReadcount(num);
BoardDTO dto = BoardMapper.getBoard(num);
req.setAttribute("getBoard", dto);
return "content";
}
@RequestMapping(value="/update.do", method=RequestMethod.GET)
public String updateFormBoard(HttpServletRequest req, int num) {
//BoardDTO dto = boardDAO.getBoard(num, "update");
BoardDTO dto = BoardMapper.getBoard(num);
req.setAttribute("getBoard", dto);
return "updateForm";
}
@RequestMapping(value="/update.do", method=RequestMethod.POST)
public String updateProBoard(@ModelAttribute BoardDTO dto, BindingResult result) {
// 예측가능한(null 세팅) 에러가 날 것 같으면 미리 처리해둘 수 있음.
// 에러가 나면 BindingResult에 담아두겠다.
if(result.hasErrors()) { // dto객체를 만드는 중 에러가 난다면
dto.setNum(0); // 0으로 세팅한다. 내가 알아서 해결하는 코드
}
//int res = boardDAO.updateBoard(dto);
int res = BoardMapper.updateBoard(dto);
return "redirect:list_board.do";
}
@RequestMapping(value="/delete.do", method=RequestMethod.GET)
public String deleteFormBoard() {
return "deleteForm";
}
@RequestMapping(value="/delete.do", method=RequestMethod.POST)
public String deleteProBoard(@RequestParam Map<String, String> params) {
// @RequestParam : 파라미터명이 Key, 파라미터값이 Value로 저장.
// 인자가 많을 경우 Map타입으로 작성해볼 수 있음
// params에는 num : num값, passwd : passwd값이 들어가있음
//int res = boardDAO.deleteBoard(Integer.parseInt(params.get("num")), params.get("passwd")); // .get(Key) = value값 꺼내짐
BoardDTO dto = BoardMapper.getBoard(Integer.parseInt(params.get("num")));
if (dto.getPasswd().equals(params.get("passwd"))) {
int res = BoardMapper.deleteBoard(Integer.parseInt(params.get("num")));
}
return "redirect:list_board.do";
}
}
@RequestMapping(value="/member_input.do", method=RequestMethod.POST)
public String InputOkMember(HttpServletRequest req, @ModelAttribute MemberDTO dto) {
int res = memberDAO.insertMember(dto);
if(res>0) {
req.setAttribute("msg", "회원 가입 성공!");
return "forward:windowClose.jsp";
} else {
req.setAttribute("msg", "회원 가입 실패! 회원가입 페이지로 이동합니다.");
req.setAttribute("url", "memberSsn.do");
return "forward:message.jsp";
}
}
// 회원 보기(memberAll.do)
MemberController.java
@RequestMapping("/memberAll.do")
public String ListMember(HttpServletRequest req, @RequestParam(required=false) String mode, String search, String searchString) {
// required=false : 만약 해당 파라미터값이 없으면 무시하고 넘어가라고 설정
// 이거 안쓰고 아래 코드에서 if (mode=null)이면 처리를 추가해도 상관없음
List<MemberDTO> list = null;
if (mode != null) {
if (search != null && searchString != null) {
list = memberDAO.findMember(search, searchString);
}
} else {
list = memberDAO.listMember();
}
req.setAttribute("listMember", list);
return "memberAll";
}
@RequestMapping(value="/member_update.do", method=RequestMethod.POST)
public String UpdateOkMember(HttpServletRequest req, @ModelAttribute MemberDTO dto) {
int res = memberDAO.updateMember(dto);
if(res>0) {
req.setAttribute("msg", "회원 수정 성공! 회원 목록 페이지로 이동합니다.");
req.setAttribute("url", "memberAll.do");
return "forward:message.jsp";
} else {
req.setAttribute("msg", "회원 수정 실패! 회원 목록 페이지로 이동합니다.");
req.setAttribute("url", "memberAll.do");
return "forward:message.jsp";
}
}
// 로그인 화면 (login.do) - GET
MemberController.java
@RequestMapping(value="/login.do", method=RequestMethod.GET)
public String LoginMember() {
return "login";
}