반응형
반응형
package com.lsj.chatting;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	@RequestMapping(value = "/getServerInfo", method = RequestMethod.GET)
	public void getServerInfo() throws UnknownHostException {
		
		System.out.println("HostName : " + InetAddress.getLocalHost().getHostName());
		System.out.println("Address : " + InetAddress.getLocalHost().getHostAddress());


        String osName = System.getProperty("os.name").toLowerCase();

        System.out.println("os.name property: " + osName);

        if (osName.contains("win")) {
            System.out.println("This is Windows");
        } else if (osName.contains("mac")) {
            System.out.println("This is Mac");
        } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) {
            System.out.println("This is Unix or Linux");
        } else if (osName.contains("sunos")) {
            System.out.println("This is Solaris");
        } else {
            System.out.println("Your OS is not support!!");
        }
		
	}
	
}
반응형
반응형

📝HttpServletRequest

클라이언트가 보낸 요청의 정보를 가지고있다.
→ 즉, 요청이 들어오면 그 요청에대한 정보를 가지고 있다.

request.getHeader("host"); → 요청한 host에 대한 정보를 가지고있다.

 

📝HttpServletResponse

HTTP 요청에 대한 응답 메시지를 생성하고, 기타 편의 기능을 제공한다.
→ 즉, 사용자에게 보낼 응답에 대한 정보를 가지고 있다.

response.setContentType("text/plain");
response.setCharacterEncoding("utf-8"); → text/plain utf-8 형태로 응답을 보내겠다.

반응형
반응형

 

plugins {
	id 'org.springframework.boot' version '2.7.4'
	id 'io.spring.dependency-management' version '1.0.14.RELEASE'
	id 'java'
}

group = 'com.lsj'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	/** 추가 라이브러리 **/
	// https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper
	implementation 'org.apache.tomcat.embed:tomcat-embed-jasper:9.0.58'

	// https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api
	implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2'

	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.security:spring-security-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

gradle 설정입니다.

package com.lsj.chatting;

import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;

/** 하기 어노테이션 사용하려면 Javax Persistence API Gradle 추가 필요 **/
@Entity // 하기 필드 기준으로 DB에  User 테이블을 생성하라는 의미
public class BlogUser {

	@Id // Primary key
	@GeneratedValue(strategy = GenerationType.IDENTITY) // 프로젝트에서 연결된 DB의 넘버링 전략을 따라간다.
	// → 즉, DB에 따라 AutoIncrement 또는 Sequence가 결정 되어서 알아서 만들어준다. (자동 증가 PK 필요함으로 이와 같은 행동 함) 
	// (MySql에서는 AutoIncrement, Oracle에서는 Sequence 사용)
	private int id;
	
	@Column(nullable = false, length = 30) // null 방지 및 길이 30
	private String username;
	
	@Column(nullable = false, length = 100) 
	private String password;
	
	@Column(nullable = false, length = 50) 
	private String email;
	
	@ColumnDefault("'user'") // → Column Default 값 String이기 때문에 ' ' 안에 넣어야한다.
	private String role; // Enum을 
	// → admin : 0
	// → user : 0
	// → manager : 0
	
	@CreationTimestamp // 현재 시각 바로 자동 입력
	private Timestamp createDate;
	
}

어노테이션을 이용해 테이블 생성하기 위한 Java 파일 입니다.

server:
  port: 8000 # 톰캣 포트 (스프링부트는 톰캣이 내장되어 있다.)
  servlet:
    context-path: /chatting # 기본 url Path 
    encoding:
      charset: UTF-8
      enabled: true
      force: true
    
spring:
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp 
      # @GetMapping 에서 함수의 return 값이 String인 경우 return 에 대한 내용은 jsp의 파일 이름입니다.
      # @GetMapping 
      # public String callJsp(){
      #   return "home" → /WEB-INF/views/home.jsp 화면을 뿌려라 
      #   일반적으로 스프링부트는 JSP를 지원하지 않기 때문에 JSP를 사용하기 위해서는 JSP 해석 템플릿 엔진인 jasper을 Gradle에서 다운로드를 해야한다.
      #}
  
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521:orcl
    username: c##root
    password: 1234
    
  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: create # 최초 전략 Applicaiton 재시작시 테이블 있으면 지우고 다시 만들게 된다.
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        # field 명 그대로 필드를 만들게 된다.
        # physical-strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
        # CamelCase 전략을 따라가는데 field 명이 myEmail인 경우 my_email로 변환시켜서 만들어준다. 
      use-new-id-generator-mappings: false 
      # false : JPA 기본 전략을 쓴다. 
      # false : JPA 기본 전략을 쓰지 않는다. → User에 선언한 GenerationType.IDENTITY을 쓰겠다
    show-sql: true
    properties:
      hibernate.format_sql: true

  jackson:
    serialization:
      fail-on-empty-beans: false

yml 파일로 JPA 사용할 설정이 들어있습니다.

 

Hibernate: 
    
    drop table BlogUser cascade constraints
Hibernate: 
    
    create table BlogUser (
       id number(10,0) generated as identity,
        createDate timestamp,
        email varchar2(50 char) not null,
        password varchar2(100 char) not null,
        role varchar2(255 char) default 'user',
        username varchar2(30 char) not null,
        primary key (id)
    )

시작시 Hibernate라는 애가 Java 파일 설정을 읽어서 Query를 생성시켜줍니다.

반응형
반응형

Lombok 같은 경우 그냥 저장소에서 다운만 받아서는 실행이 불가능하고 jar파일을 실행시켜서 해당 프로젝트가 롬복을 사용한다는 설정을 해줘야합니다. Lombok에 기능은 필드명만 넣어주고 어노테이션만 설정하면 생성자 및 Getter 및 Setter를 안 만들어도 자동 생성해줍니다.

 

Maven의 경우 여기에 들어있고

C:\Users\${사용자계정}\.m2.....

 

Gradle의 경우 여기에 들어가있습니다.

C:\Users\${사용자계정}\.gradle\caches\modules-2\files-2.1\org.projectlombok\lombok\1.18.24

 

 

cmd에서 jar 실행시켜주면 이렇게 나옵니다.

 

Specifiy location을 누른 후 sts4(툴)을 선택해줍니다.

Install 눌러서 툴에 설정을 설치하시면 됩니다. 그 후 sts4 재실행 해주세요

 

package com.lsj.chatting;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

// @Getter // Getter 생성
// @Setter // Setter 생성 
// @RequiredArgsConstructor // final 필드가 존재할 경우 생성자
@Data // Getter + Setter 생성
// @AllArgsConstructor // 생성자 생성
@NoArgsConstructor // 기본생성자
public class Account {

	// private final String id; // DB에서 값을 받아와 수정할 일이 없을 때는 final 로 쓰는게 trend
	// private final int password; // DB에서 값을 받아와 수정할 일이 없을 때는 final 로 쓰는게 trend 
	private String id;
	private int password;
	
	@Builder // 내가 원하는 생성자 파라미터 지정 가능 (자세한건 TestController에서 봐주세요)
	public Account(String id, int password) {
		this.id = id;
		this.password = password;
	}
	
	
	
}
package com.lsj.chatting;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	@GetMapping("/test/get")
	public String hello(Account account) {
		
		account.setId("hello");
		account.setPassword(1234);
		
		System.out.println("id : " + account.getId() + " password :" + account.getPassword() );
		// id : hello password :1234 출력
		
		account = Account.builder().password(0).build(); // password만 포함된 생성자
		System.out.println("id : " + account.getId() + " password :" + account.getPassword() );
		// id : null password :0
		
		Account account2 = Account.builder().password(150).id("halo").build(); // id, password가 포함된 생성자 
		System.out.println("id : " + account2.getId() + " password :" + account2.getPassword() );
		// id : halo password :150
		
		// @Builder는 다양하게 생성자를 오버로딩해서 만들 수 있다. → 
		return "<h1> get </h1>";
		
	}

	@DeleteMapping("/test/delete")
	public String delete() {
		return "<h1> delete </h1>";
	}
	
	@PostMapping("/test/post")  // Body : json → application/json (Text → text/plain로 요청시 에러 발생 [자동매핑이 안 되어서])
	public String post(@RequestBody Account account) { // MessageConverter라는 Class가 자동 Injection을 해준다.
		return "id : " + account.getId() + "\n password : " + account.getPassword(); 
		// {id:1,password:1234} 으로 요청 
	}
	
	@PostMapping("/test/post2") // Body : Text → text/plain 
	public String post2(@RequestBody String text) { // @requestBody body 데이터를 받기 위해 필요
		return text; // 정말로 맛있어요 으로 요청 
	} 
	
	@PutMapping("/test/put")
	public String put() {
		return "<h1> put </h1>";
	}
	
}
반응형
반응형

HTTP 통신 Request와 Response를 보기 좋게 보여주고 요청을 쉽게 도와주는 프로그램이다.

 

- 설치

https://chrome.google.com/webstore/search/postman?hl=ko

 

Chrome 웹 스토어

Chrome에 사용할 유용한 앱, 게임, 확장 프로그램 및 테마를 찾아보세요.

chrome.google.com

 

설치 후에 사용방법은 간단합니다.

 

 

Method가 Http 통신 방식을 정하시고 URL을 적어주시면 됩니다.

GET의 경우 웹브라우저로 요청해도 오니 POST방식을 알려드리겠습니다.

 

 

package com.lsj.chatting;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	@GetMapping("/test/get")
	public String hello() {
		return "<h1> get </h1>";
	}

	@DeleteMapping("/test/delete")
	public String delete() {
		return "<h1> delete </h1>";
	}
	
	@PostMapping("/test/post")  // Body : json → application/json (Text → text/plain로 요청시 에러 발생 [자동매핑이 안 되어서])
	public String post(@RequestBody Account account) { // MessageConverter라는 Class가 자동 Injection을 해준다.
		return "id : " + account.getId() + "\n password : " + account.getPassword(); 
		// {id:1,password:1234} 으로 요청 
	}
	
	@PostMapping("/test/post2") // Body : Text → text/plain 
	public String post2(@RequestBody String text) { // @requestBody body 데이터를 받기 위해 필요
		return text; // 정말로 맛있어요 으로 요청 
	} 
	
	@PutMapping("/test/put")
	public String put() {
		return "<h1> put </h1>";
	}
	
}
package com.lsj.chatting;

public class Account {

	private String id;
	private int password;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public int getPassword() {
		return password;
	}
	public void setPassword(int password) {
		this.password = password;
	}
	
	
}

기본적으로 form 따위 방식으로 보낼 때 x-www-form-urlencoded 방식으로 body에 담아 보냅니다. 

 

Header에 보시면 text/plain으로 보낸 걸 알 수 있습니다.

 

Body에 담아서 보낼 경우 Text 방식과 Json 방식을 설정할 수 있습니다.

 

반응형
반응형

src/main/resources/application.properties → application.yml으로 수정

 

spring:
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521:orcl
    username: c##root
    password: 1234

주의) 탭사용 금지, 무조건 띄어쓰기로 구분해주세요

키: 값 형태에서 콜론 다음 띄어쓰기 꼭 해야합니다.

 

spring.datasource.driver-class-name

spring.datasource.url

spring.datasource.username

spring.datasource.password

→ yml의 계층구조는 위에 구조를 계층화 시켜서 간단하게 표현한 것입니다.

 

이제 Gradle에서 주석처리한 JPA를 Gradle로 다운받고 Application 시작을 하면 잘 접속이 되는 걸 확인할 수 있습니다.

(JPA을 사용하는데 DB 접속을 안 시켜놓으면 Application 시작시 에러나옴)

 

yml이란

JSON, XML과 형태나 형식이 유사합니다. 공백 두개로 계층을 구분합니다.

 

 

 

 

 

반응형
반응형

 

병렬 작업 처리가 많아지면 스레드 개수가 무한정으로 증가하고 CPU가 바빠지며 메모리 사용량이 늘어난다.

따라서 애플리케이션의 성능이 급격하게 저하되게 된다.

 

스레드 풀

작업 처리에 사용되는 스레드를 제한된 개수 만큼 미리 생성해서 작업 큐에 쌓여지는 작업들을 하나씩 스레드가 맡아서 처리한다. 제한을 걸기 때문에 무한정으로 증가하지 않으며 서버가 뻗지 않게 된다.

 

코어 스레드 수  

최소 스레드 수 (60초 동안 추가된 스레드가 아무 작업 하지 않으면 놀고 있는 스레드가 존재해 없애야한다.)

 

스레드풀의 스레드는 기본적으로 데몬 스레드가 아니기 때문에 main 스레드가 종료되더라도 계속 실행 되므로

반드시 종료시키려면 스레드 풀을 따로 종료시켜야한다.

 

 

 

반응형
반응형
package runnable_jar;

public class PrintThread extends Thread {
	@Override
	public void run() {
		while (true) {
		}
	}
}
package runnable_jar;

import java.util.Map;
import java.util.Set;

public class InterruptExample {

	public static void main(String[] args) {

		PrintThread printThread = new PrintThread();
		printThread.setName("Print Thread");
		printThread.setDaemon(true);
		printThread.start();
		
		Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
		Set<Thread> threads = map.keySet();
		for(Thread thread : threads) {
			System.out.println("Name : " + thread.getName() + ((thread.isDaemon() ? " 데몬" : "주")));
			System.out.println("\t" + "소속그룹 : " + thread.getThreadGroup().getName());
			System.out.println();
		}
	}
	/** 기본 스레드 그룹 **/
	// system : JVM 운영에 필요한 스레드를 포함
	// main : 메인 스레드를 포함 (Print Thread는 Main Thread의 데몬 스레드이기 때문에 main 소속)
	
//	Name : Notification Thread 데몬
//	소속그룹 : system
//
//	Name : main주
//		소속그룹 : main
//	
//	Name : Signal Dispatcher 데몬
//		소속그룹 : system
//	
//	Name : Common-Cleaner 데몬
//		소속그룹 : InnocuousThreadGroup
//	
//	Name : Finalizer 데몬
//		소속그룹 : system
//	
//	Name : Print Thread 데몬
//		소속그룹 : main
//	
//	Name : Reference Handler 데몬
//		소속그룹 : system
//	
//	Name : Attach Listener 데몬
//		소속그룹 : system


}

 

 

 

 

package runnable_jar;

public class PrintThread extends Thread {

	// 스레드 그룹 정해주는 생성자
	public PrintThread(ThreadGroup threadGroup, String threadName) {
		super(threadGroup, threadName);
	}
	
	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				System.out.println(getName() + " interrupted");
				break;
			}
		}
		System.out.println(getName() + "종료됨");
	}
	

}
package runnable_jar;

public class ThreadGroupExample {

	public static void main(String[] args) {

		ThreadGroup myGroup = new ThreadGroup("myGroup"); // main - myGroup (계층도)
		PrintThread printThreadA = new PrintThread(myGroup, "printThreadA"); // main - myGroup - printThreadA
		PrintThread printThreadB = new PrintThread(myGroup, "printThreadB"); // main - myGroup - printThreadB
		
		printThreadA.start();
		printThreadB.start();
		
		System.out.println("[main 스레드 그룹 list() 메소드 출력 내용]");
		ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
		mainGroup.list();
		System.out.println();
		

		
//		[main 스레드 그룹 list() 메소드 출력 내용]
//				java.lang.ThreadGroup[name=main,maxpri=10]
//				    Thread[main,5,main]
//				    java.lang.ThreadGroup[name=myGroup,maxpri=10]
//				        Thread[printThreadA,5,myGroup]
//				        Thread[printThreadB,5,myGroup]

		myGroup.interrupt(); // 상위 스레드 그룹에서 interrupt 발생시 하위 스레드도 전부 interupt 발생
		
//		printThreadA interrupted
//		printThreadA종료됨
//		printThreadB interrupted
//		printThreadB종료됨
	}

}
반응형
반응형

1. Runnable
Runnable은 이름부터 인터페이스의 느낌이 강하다.
implements Runnable 을 통해서 Runnable 인터페이스를 구현할 수 있다.

Runnable 인터페이스를 구현하게되면 재사용성이 높고, 코드의 일관성을 유지할 수 있어서 Thread보다 더 효율적인 방법이라 할 수 있다.

2. Thread
상속을 받아 사용해야 하기 때문에 다른 클래스를 상속받아 사용할 수 없다는 단점이 있다.
따라서 일반적으로는 Runnable 인터페이스를 구현해서 스레드를 사용한다.

반응형