반응형
반응형

 

<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
</dependency>

 

 

<!-- 경로 : main/resources/log4j2.xml -->
<?xml version="1.0" encoding="UTF-8"?>

<configuration status="DEBUG">

	<!-- 콜솔 -->
	<Console name="console" target="SYSTEM_OUT">
		<PatternLayout
			pattern="%d{yyyy-MM-dd hh:mm:ss} %5p [%c] %m%n" />
	</Console>

	<Appenders>
		<!-- 파일 -->
		<RollingFile name="as_api_param">
			<FileName>/home/Search/logs/search/search_param.log</FileName>
					<FilePattern>/home/Search/logs/search/search_param_%d{yyyy-MM-dd}.log
			</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
			</Policies>
		</RollingFile>

		<RollingFile name="as_api_uri">
			<FileName>/home/Search/logs/search/search_uri.log</FileName>
			<FilePattern>/home/Search/logs/search/search_uri_%d{yyyy-MM-dd}.log</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
			</Policies>
		</RollingFile>
	</Appenders>

	<loggers>
		<Logger name="AS_API_PARAM" level="DEBUG" additivity="false">
			<AppenderRef ref="as_api_param" />

		</Logger>
		<Logger name="AS_API_URI" level="DEBUG" additivity="false">
			<AppenderRef ref="as_api_uri" />
		</Logger>
		<Logger name="CONSOLE" level="DEBUG" additivity="false">
			<AppenderRef ref="console"/>
		</Logger>
	</loggers>


</configuration>

Console → Console에 출력

RollingFile → 로그 찍는 형식 (Rolling이란 파일을 계속 갱신하는 것을 의미)
name → 로그 찍는 형식의 이름 (AppenderRef에서 사용)

FileName → 로그 저장경로와 로그 이름
FilePattern → Rolling시 저장될 위치및 로그파일 이름
PatternLayout  → 로그에 출력할 로그 내용 형식
%d{yyyy-MM-dd HH:mm:ss} → yyyy-MM-dd HH:mm:ss 로그 찍힌 시각
%5p → 로그형식
%C → 클래스명 표시
%m → 로그 출력 본 내용
%n → 각 플랫폼에 맞는 개행



TimeBasedTriggeringPolicy → 로그에 사용할 정책
interval → interval 단위로 로그 파일 새로 생성 (롤오버라고 한다)
FilePattern 에 적인 형식이 yyyy-MM-dd일 경우  interval=1 기준 1일 단위
yyyy-MM-dd-hh 일 경우는 1시간 단위
moulate → false인 경우 application 시작 시각으로부터가 기준이고 true인 경우 정각인 시각마다 롤오버가 일어난다.

Loggers → 위에 선언한 로그 형식중 사용할 로그 형식 선언
Logger 
 - name → java파일에서 사용할 Log의 이름
 - level → 로그 Level 해당 로그 이상만 로그 적재
 - addtivity → 중복 로깅 여부 (RollingFile name이 여러 AppenderRef ref에서 참조될 시 한번만 찍게 된다.)

package com.company.AS_API;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;




@Controller
public class companyController {
	
	@RequestMapping(value = "/logs", method = RequestMethod.GET)
	public void makeLogs {
		
		Logger console = LogManager.getLogger("CONSOLE");
		Logger APIParamLogger = LogManager.getLogger("AS_API_PARAM");
		Logger APIURILogger = LogManager.getLogger("AS_API_URI");

		// 로그 찍기
		APIParamLogger.debug("debug 입니다.");
		APIParamLogger.info("info 입니다.");
		APIParamLogger.warn("warn 입니다.");
		APIParamLogger.error("error 입니다.");
		APIParamLogger.fatal("fatal 입니다.");
	}
}

 

 

 

─── 참고 RollingFile + Console ── 

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

	<Appenders>
		<!-- 콜솔 -->
		<Console name="console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{yyyy-MM-dd hh:mm:ss} %5p [%c] %m%n" />
		</Console>
		<RollingFile name="admin_real">
			<FileName>/home/Search/logs/admin/AA.log</FileName>
			<FilePattern>/home/Search/logs/admin/AA_%d{yyyy-MM-dd}.log</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
			</Policies>
		</RollingFile>
		<RollingFile name="admin_local">
			<FileName>D://logs//aa.log</FileName>
			<FilePattern>D://logs//aa_%d{yyyy-MM-dd}.log</FilePattern>
			<PatternLayout>
				<Pattern>%d{yyyy-MM-dd HH:mm:ss} %5p [%c] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"	modulate="true" />
			</Policies>
		</RollingFile>
	</Appenders>

	<loggers>
		<Logger name="ADMIN_LOGGER_LOCAL" level="DEBUG"
			additivity="false">
			<AppenderRef ref="console" />
			<AppenderRef ref="admin_local" />
		</Logger>

		<Logger name="ADMIN_LOGGER_REAL" level="DEBUG"
			additivity="false">
			<AppenderRef ref="console" />
			<AppenderRef ref="admin_real" />
		</Logger>
		
		
	</loggers>


</configuration>

 

 

형식 참고 블로그 : http://changpd.blogspot.com/2013/05/spring-lo4j.html

반응형
반응형
package global.configuration;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

import org.ini4j.Ini;
import org.ini4j.InvalidFileFormatException;

public class iniTest {

	static final String INI_PATH = "src/main/java/global/configuration/properties.ini"; 
	
	public static void main(String[] args) throws InvalidFileFormatException, IOException {
		
		/** ini4j 라이브러리 이용 하지 않기 **/
		// ini 파일 내용
		// mode = external_local

		Properties prop = new Properties();
		prop.load(new FileInputStream(INI_PATH));
        
		System.out.println(prop.getProperty("mode")); // external_local
		
		
		/** ini4j 라이브러리 사용 → 대괄호 읽을 수 있음**/
		// ini 파일 내용 
		// [mode]
		// mode = external_local

		Ini ini = new Ini();
		File iniFile = new File(INI_PATH);
		ini = new Ini(iniFile);
		
		System.out.println(ini.get("mode", "mode")); // external_local
		
		
	}

}
<!-- https://mvnrepository.com/artifact/org.ini4j/ini4j -->
<dependency>
    <groupId>org.ini4j</groupId>
    <artifactId>ini4j</artifactId>
    <version>0.5.4</version>
</dependency>
반응형
반응형
package com.lsj.blog.handler; // Exception 처리 Handler를 따로 패키지를 구성한다.

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

@ControllerAdvice // 어떤 Exception이 오든 이 페이지로 오게 된다.
@RestController
public class GlobalExceptionHandler {
	
	// @ExceptionHandler는 Controller계층에서 발생하는 에러만 잡는다.
	@ExceptionHandler(value=Exception.class) // 모든 부모 Exception 
	public String handleException(Exception e) {
		return "<h1>" + e.getMessage() + "</h1>";
	}
	
	@ExceptionHandler(value=IllegalArgumentException.class) // 해당 IllegalArgumentException이 발생할 경우 밑에 함수가 작동한다.
	public String handleArgumentException(IllegalArgumentException e) {
		return "<h1>" + e.getMessage() + "</h1>";
	}
}
반응형
반응형
@DeleteMapping("dummy/user/{id}")
public String deleteUser(@PathVariable int id) {

    /** 방법1 (예외처리가 안 되어있음)**/
    //userRepository.deleteById(id);

     /** 방법2 **/
    try {
        userRepository.deleteById(id);
    }catch (Exception e) {
        return "삭제에 실패했습니다. 해당 id는 존재하지 않습니다.";
    }

    return "삭제되었습니다.";
}
반응형
반응형

 

영속성 컨텐스트란 엔티티를 영구 저장하는 환경으로 애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스라고 생각하면 된다.

JPA는 영속성 컨텍스트라는게 존재하고 그 안에 캐시가 있어서 DB에 접근 안 하고 캐시에 존재하는 데이터는 빠르게 가져오거나 DB에 부담을 줄일 수 있습니다. 그리고 그 캐시안에 있는 걸 영속화 되었다라고 표현합니다.

 

📝Insert

Insert시 영속성 컨텍스트에 해당 값이 올라가게 되고 flush해 영속성 컨텍스트에 있는 데이터를 DB에 데이터를 넣게 됩니다.

 

📝Select

Select시 DB에 해당 데이터를 영속성 컨텍스트에 올리게 됩니다. 그 후 컨트롤러에서는 영속성 컨텍스트에 있는 값을 가져가게 됩니다.

 

📝Update

Update의 경우 Select와 같은 동작이 선행이 되어서 영속성 컨텍스트에 올라가게 되고 그 후 업데이트된 값을 다시 영속화 시키고 DB에 flush해 데이터를 업데이트 시킵니다.

 

📝더티체킹

Update와 같은 행위를 Transaction 어노테이션을 이용해 하는 걸 더티체킹이라고 합니다.

Transaction 어노테이션이 선언된 곳에서 영속성 컨텍스트에 변경이 일어날 시 자동으로 데이터베이스에 반영하는 JPA 특징입니다.

 

 

@Transactional // 함수 종료시 자동으로 DB Commit (영속성컨테이너 데이터를 DB로 Flush)
// Update ( Put방식은 Body에 Json만 인식하고 @RequestBody는 두개 이상 사용이 불가능 (객체에 담던가 해야한다.)
@PutMapping("/dummy/users/{id}") 
public String updateUser(@PathVariable int id, @RequestBody BlogUser requestUser) {
    System.out.println("id : " + id);
    System.out.println("password : " + requestUser.getPassword());
    System.out.println("email : " + requestUser.getEmail());

    BlogUser user = userRepository.findById(id).orElseThrow(() ->{
        return new IllegalArgumentException("수정에 실패하였습니다.");
    });

    user.setPassword(requestUser.getPassword());
    user.setEmail(requestUser.getEmail());

    /** @Transactional 사용 안 할시 **/
    // save 함수는 id를 전달하지 않으면 insert
    // save 함수는 id를 전달하면 해당 id 존재시 udpate 없으면 insert
    // userRepository.save(user);

    return id + "가 update 가 되었습니다. ";
}

 

 

@Transaction 다른 예제

@RestController
public class DummyController {

	@Autowired // DI
	private UserRepository userRepository;
	
	@PostMapping("/api/user")
	//@Transacitonal
	public ResponseDto<String> save(@RequestBody BlogUser user){

		BlogUser usre2 = new BlogUser();
		
		Random random = new Random();

		usre2.setUsername(String.valueOf(random.nextInt(10)));
		usre2.setPassword("abc@naver.com");
		usre2.setEmail("abc@naver.com");
		userRepository.save(usre2); 
		
		user.setRole(RoleType.USER); // Enum을 이용한 방식을 통해 Setter 주입 실수를 방지할 수 있다. 
		join(user);
	
		return new ResponseDto<String>(HttpStatus.OK .value(), "1");
		// new ResponseDto<String>(HttpStatus.OK, result);
	}
	
	@Transactional // Transaction 처리하겠다. 성공시에만 Commit 
	public void join(BlogUser user) { 
		userRepository.save(user); // UserRepostiory에 save하면 DB 테이블에 insert가 된다.
	}
	
 }
 
 
 데이터 Body 형식 →
 {
    "username" : "lee6",
    "password" : "1234",
    "email" : "tjdwo37@naver.com"
}
 
 
 
 - @Transaction이 join 함수에 있는 경우
join 함수를 실행시에 에러가 날시 join함수 내용만 rollback
위에 랜덤함수로 UserName을 넣고 insert 과정은 join함수를 안 쓰기 때문에 
해당 API 계속 호출시 랜덤함수로 UserName 넣는 데이터 계속 insert는 되고 있음

- @Transcaation을 api 함수에 넣은 경우
api에서 에러가 날시 모든 내용을 rollback하기 때문에 위와 같이 랜덤함수로 UserName넣고 insert하는 과정도
rollback이 되어서 데이터가 계속 누적되지 않는다.
package com.lsj.blog;

import java.sql.Timestamp;
import java.util.List;

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

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

import com.lsj.blog.model.RoleType;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/** 하기 어노테이션 사용하려면 Javax Persistence API Gradle 추가 필요 **/
//@DynamicInsert // null 인 값일 때는 무시하고 Default값으로 넣어준다
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@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, unique=true) // null 방지 및 길이 30 + 중복값 방지
	private String username;
	
	//@ColumnDefault(" 'no password' ") //→ @DynamicInsert 와 같이 사용한다. null일시에는 ColumnDefault에 선언된 값(no password)으로 넣어준다.   
	@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을 
	
	@Enumerated(EnumType.STRING) // DB에는 RoleType이라는 타입이 없기 때문에 String 이라고 선언
	private RoleType role;
	
	@CreationTimestamp // 현재 시각 바로 자동 입력
	private Timestamp createDate;
	
}

 

반응형
반응형
import java.util.List;
import java.util.function.Supplier;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import com.lsj.blog.model.RoleType;
import com.lsj.blog.repository.UserRepository;


@GetMapping("/dummy/user/{id}")
public BlogUser detail(@PathVariable int id) { // PathVariable은 들어온 id값에 따른 동적 처리 {id}


    // BlogUser user = userRepository.findById(id); // findById의 return 타입은 Optional
                                                    // → 자바에서 DB 데이터를 못찾아오게 되면 user가 null이 되어 return이 되기 때문에
                                                    // Optional로 객체를 감싸서 가져올테니 null인지 아닌지 판단해서 return 해라
    /** 방법1 **/
    // userRepository.findById(id).get(); // null 그런거 상관없이 가져오겠다. (위험) 

    /**  방법 2
    BlogUser user = userRepository.findById(id).orElseGet(new Supplier<BlogUser>(){
        @Override
        public BlogUser get() { // 값이 없는 경우 BlogUser 객체 생성해 주입 (Null 가능성은 없음)
            return new BlogUser();
        }
    });
    **/

    /** 방법3 (선호) 해당 에러 발생시 Throw **/
    BlogUser user = userRepository.findById(id).orElseThrow(new Supplier<IllegalArgumentException>(){
        @Override
        public IllegalArgumentException get() {
            return new IllegalArgumentException("해당 유저는 없습니다. id : " + id);
        }
    });

    return user;
}

// 페이지리스트 모두 출력
@GetMapping("/dummy/list")
public List<BlogUser> list(){
    return userRepository.findAll();
}

// 페이지네이션
// size → 보여줄 개수
// sort → order by 할 필드
// direction  → 오름차순 또는 내림차순
// dummy/list/page?page=0 일시 id 3번, 2번 노출  | page=1로 호출시 id 1번 노출
// 아무것도 입력안 할시 ?page=0과 동일
@GetMapping("dummy/list/page")
public Page<BlogUser> pageList(@PageableDefault(size=2, sort="id", direction = Sort.Direction.DESC) Pageable pageable){
    Page<BlogUser> users = userRepository.findAll(pageable);
    return users;
}

 

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import com.lsj.blog.model.RoleType;
import com.lsj.blog.repository.UserRepository;

@RestController
public class DummyController {

	@Autowired // DI
	private UserRepository userRepository;
	
	@PostMapping("/dummy/join")
	public String join(BlogUser user) { 
		
		//user.setRole("user"); // @DynamicInsert처럼 계속 어노테이션을 붙히다보면 어노테이션 지옥에 빠지기 때문에 직접 Setter에 주입해 어노테이션을 줄일 수 있지만 실수할 수 있다.
		user.setRole(RoleType.USER); // Enum을 이용한 방식을 통해 Setter 주입 실수를 방지할 수 있다. 
		userRepository.save(user); // UserRepostiory에 save하면 DB 테이블에 insert가 된다.
		
		return "회원가입이 완료되었습니다.";
	}
}

DummyController.java

 

package com.lsj.blog.model;

//데이터 강제할 수 있다. (데이터의 도메인화 → 강제)
public enum RoleType {
	USER, 
	ADMIN 
}

RoleType.java

 

package com.lsj.blog.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.lsj.blog.BlogUser;

// extends JapRepository가 있는 경우 @Repository 생략가능
// JpaRepostiory는 다양한 기능을 가지고 있다. findAll (모든 레코드 select) 페이징해서 보내줄 수 있는 기능도 존재
public interface UserRepository extends JpaRepository<BlogUser, Integer>{ // BlogUser의 Repository이고 PK는 Integer이다.
	
}

UserRepository.java

 

package com.lsj.blog;

import java.sql.Timestamp;
import java.util.List;

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

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

import com.lsj.blog.model.RoleType;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/** 하기 어노테이션 사용하려면 Javax Persistence API Gradle 추가 필요 **/
@DynamicInsert // null 인 값일 때는 무시하고 Default값으로 넣어준다
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@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, unique=true) // null 방지 및 길이 30 + 중복값 방지
	private String username;
	
	@ColumnDefault(" 'no password' ") //→ @DynamicInsert 와 같이 사용한다. null일시에는 ColumnDefault에 선언된 값(no password)으로 넣어준다.   
	@Column(nullable = true, length = 100) 
	private String password;

	@Column(nullable = false, length = 50) 
	private String email;
	
	//@ColumnDefault("'user'") // → Column Default 값 String이기 때문에 ' ' 안에 넣어야한다.
	//private String role; // Enum을 
	
	@Enumerated(EnumType.STRING) // DB에는 RoleType이라는 타입이 없기 때문에 String 이라고 선언
	private RoleType role;
	
	@CreationTimestamp // 현재 시각 바로 자동 입력
	private Timestamp createDate;
	
}


/**
위와 같은 엔터티일 때 세이브할 데이터 형식 예제
{
    "username" : "lee6",
    "email" : "abc@naver.com"
}

결과 → 2	22/12/03 12:31:26.986000000	tjdwo37@naver.com	no password	USER	lee6
**/

BlogUser.java

반응형
반응형

📝Tomcat 큰 3가지 구성

Coyote : Tomcat TCP 프로토콜 지원
Catalina : Java Servlet을 호스팅 해준다.
Jasper : JSP 페이지 요청 처리 Servlet

 

📝톰캣 동작 구조

Tomcat Server가 그 밑에 Service 객체를 생성한다 (그 하위에는 Engine, Connector(호출 포트), Host, Context(URI Mapping) 등이 존재)

HTTP 통신 요청 → 호출 포트에 해당하는 Connector 연결 → Service → Engine → Host → Context(기본적으로 webapps에 있는 곳 참조해 프로젝트 URI Mapping → 프로젝트 내 web.xml 읽기 → 프로젝트 내 web.xml 기반으로 프로젝트 URI 매핑

 

 


하나의 Server에는 여러개 Service가 존재할 수 있다.
하나의 Service에는 1개의 Engine과 여러개의 Connector로 구성
하나의 Engine에는 여러개 Host 존재할 수 있다.
하나의 Host에는 여러개 Context가 존재할 수 있습니다.

 

Tomcat Server → Engine(Connector로 통해 전달) → Host → Context 

[Tomcat에서는 server.xml에 적혀있는 내용을 가지고 객체를 만드는 거라고 생각하면 된다. 그렇기 때문에 Connector에 포트번호를 적어두면 어떤 Service를 이용할지 방향을 알려준다]

 

📝Server

port : Shutdown 명령을 보낼 수 있는 TCP/IP 주소

<Server port="8005" shutdown="SHUTDOWN">

 

📝Service

Serivce의 유일한 이름으로 Log를 남길 때 사용한다 (Catalina.out)

<Service name="Catalina">

 

 

📝Connector

 

특정 TCP port에서 request들을 listen해 engine으로 보내준다.

  • port
    • 리슨할 포트
  • protocol
    • TCP/IP 방식 
  • HTTP/1.1
    • 기본적으로 Connection당 하나의 요청을 처리 하도록 설계 동시 전송이 불가능하고 요청과 응답이 순차적으로 이뤄진다
  • HTTP/2
    • HTTP1.1을 완전하게 재작성한 것이 아니라 프로토콜의 성능에 초첨을 맞춰 수정한 버전 기본적으로 connection 한 개로 동시에 여러 개의 메시지를 주고 받을 수 있으며, 응답은 순서에 상관없이 stream으로 주고 받는다
  • AJP
    • "Apache JServ Protocol"의 약자로, Tomcat과 웹 서버(주로 Apache) 간의 통신을 위한 프로토콜로 Web서버인 Apache에서 어떤 포트를 들어오면 포트포워딩할 지에 대한 포트 설정을하고 Tomcat도 이에 대한 걸 받기 위한 프로토콜 설정 및 포트 개방을 한다
<!-- Apache 설정 -->
<VirtualHost *:80>
    ServerName yourdomain.com
    # 기타 설정

    ProxyPass / ajp://localhost:8009/    # Tomcat과의 AJP 연결 설정
    ProxyPassReverse / ajp://localhost:8009/
</VirtualHost>

<!-- Tomcat 설정 -->
<Connector protocol="AJP/1.3" port="8009" redirectPort="8443" />


위 프로토콜의 동작 방식 설정
- BIO : Tomcat 7 기본 방식 하나의 Thread가 하나의 Connection을 담당
- NIO :  Tomcat 8.5 기본 방식 하나의 Thread가 하나 이상의 Connection을 담당
- APR :  10.x 버전 부터 ARP 방식 삭제

<Connector port="7104" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="7004" URLEncoding="UTF-8" />

 

 

📝Thread Pool 설정

maxThreads : Connector가 생성할 수 있는 최대 Thread 수
maxConnections : 동시 처리 가능한 최대 Connection 수
maxSpareThreads : 최소로 실행을 유지할 thread 수
acceptCount : thread가 꽉 찼을 때 queue에 저장 가능한 최대 request 수

Thread Pool
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150", maxConnections >
공유 Thread Poll
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>

 

 

📝 Engine

name : Engine의 유일한 이름으로 Log를 남길 때 사용한다.
defaultHost ?

<Engine name="Catalina" defaultHost="localhost">

 

 

📝Host

name : 유일한 가상 Host명 (http://hostname/~)
appBase : app 폴더 (default webapps) Host마다 다른 appBase를 지정할 수 있다. (여러개 Domain 효율적 관리가능)
autoDeploy : appBase에 변동사항이 있을 때 자동으로 Deploy(배포) 해준다.
unpackWARs : war파일 deploy 설정 여부

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

 

 

📝Context

Host안에 있으며 하나의 WebApplication이며 주로 .war 형태로 배포됩니다.

docBase : 호출할 경로 URI이다. (/ABC/testing.jsp 호출시 /webapps/DEF/testing.jsp를 호출하게 된다.)

path : 실제 호출시킬 경로이다

만약 Context가 없으면 기본적으로 docBase는 webapps안에 있는 폴더 이름을 따라가게 된다.

즉, webapps/ABC 폴더가 존재시 /ABC/ 이런식으로 호출함

<Host name="localhost" appBase="webapps"
            unpackWARs="true" autoDeploy="true">
  <Context docBase="ABC" path="/DEF" reloadable="true"></Context>

 

 

 

 

🔗 참고 및 출처

https://velog.io/@hyunjae-lee/Tomcat-2-%EA%B5%AC%EC%A1%B0

 

Tomcat - (2) 구조

Tomcat의 구조에 대해 자세히 알아봅니다.

velog.io

 

https://bogyum-uncle.tistory.com/m/219

 

[Tomcat] server.xml 구조

톰캣의 server.xml 은 메인 설정 파일이며, Tomcat startup 초기 설정을 명세하는 책임이 있음 1. server.xml 태그 예시 2. 태그 상세 태그 설명 Server root element, shutdown port 지정, 전체 설정파일의..

bogyum-uncle.tistory.com

https://ijbgo.tistory.com/m/26

 

HTTP/1.1 VS HTTP/2

HTTP/1.1 동작 방식 HTTP/1.1는 기본적으로 Connection당 하나의 요청을 처리 하도록 설계동시 전송이 불가능하고 요청과 응답이 순차적으로 이뤄짐HTTP 문서 안에 포함된 다수의 리소스 (Images, CSS, Script)

ijbgo.tistory.com


https://velog.io/@wiostz98kr/HTTP1.1%EA%B3%BC-HTTP2.0%EC%9D%98-%EC%B0%A8%EC%9D%B4-e2v4x4t1

 

반응형
반응형

- 톰캣 포트 변경

${tomcat 설치경로}/conf/server.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at
...
-->
...
<Server port="8005" shutdown="SHUTDOWN">
...

    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000"
               redirectPort="8443" />

....

      </Host>
    </Engine>
  </Service>
</Server>

Connector port="8080" → Connector port="${바꿀 포트번호}" 로 변경

 

SSL 인증서 발급

 

 

 

반응형