pem 키가 필요한 인스턴스에 scp 명령어로 파이
scp -i [pem파일경로] [업로드할 파일 이름] [계정명]@[ip 주소]:~/[경로] https://ict-nroo.tistory.com/40
scp -i [pem파일경로] [업로드할 파일 이름] [계정명]@[ip 주소]:~/[경로] https://ict-nroo.tistory.com/40
배경 vscode로 vue.js 프로젝트를 열었는데, eslint와 prettier가 적용되지 않고 제목과 같은 오류가 발생했다. 해결 방법 vscode에서 eslintrc.js 설정 파일을 자동으로 찾지 못 하고있다. vscode에서는 기본적으로 열어 놓은 디렉토리의 최상단에서 설정 파일을 찾는다. vscode에서 별도의 설정이 필요했다. settings.json "eslint.workingDirectories": [ { "mode": "auto" } ] 참고 자료 https://stackoverflow.com/questions/71271760/parsing-error-no-babel-config-file-detected-when-ide-not-open-at-vue-projects
목표 pagination 쿼리 최적화 방법을 이해한다. pagination을 사용중일 때 데이터 개수를 어떻게 구할지 이해한다. Pagination 최적화 방법 offset의 문제점 단순하게 pagination을 구현할 때, offset과 limit을 사용해서 구현한다. select * from news order by date desc, id desc limit 50 offset 4950; create index .. on news(date, id); 이 방식은 5000개의 데이터를 가져와서 4950개의 행을 버리는 방식이다. 페이지가 넘어갈수록 심각하게 느려지는 문제가 있다. 중간에 데이터가 추가되는경우, 다음 페이지네이션에 중복된 데이터가 보일 수 있다....
@Configuration public class PageableConfig implements WebMvcConfigurer { private static final int MAX_PAGE_SIZE = 16; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver(); resolver.setOneIndexedParameters(true); resolver.setMaxPageSize(MAX_PAGE_SIZE); argumentResolvers.add(resolver); } } setOneIndexedParameters(true): 페이징 인덱스가 1부터 시작하도록 설정. 이 경우에도 PageRequest.of(1, 16) 을 호출하면 두 번째 페이지가 가져와지니 주의 해야된다. Pageable을 직접 커스터마이징 하는 것이 아니라, 컨트롤러에서 Pageable을 파라미터로 받을 때 1이 자동으로 0으로 바뀌는 것으로 추측 된다. setMaxPageSize(MAX_MAGE_SIZE): 한 페이지로 불러 올 수 있는 최대 크기를 지정한다....
Optional<T> 기준으로 Optional.orElse()는 인자로 T 객체를 받고 orElseGet은 Supplier<? extends T> 를 받는다. orElse에 메소드를 넣어두면 null이든 아니든 항상 실행되고 orElseGet은 null일 경우에만 실행된다. 함수를 호출해야 되는 경우에는 가능하면 orElseGet을 사용하는게 좋아보인다. // Always get heavy resource getResource(resourceId).orElse(getHeavyResource()); // Get heavy resource when required. getResource(resourceId).orElseGet(() -> getHeavyResource()) 참고 자료 https://stackoverflow.com/questions/33170109/difference-between-optional-orelse-and-optional-orelseget https://velog.io/@joungeun/orElse-vs-orElseGet
목표 OpenLDAP 서버를 실행한다. 아래 그림대로 엔트리를 구성한다. 서버 구동 docker container로 서버 구동 https://hub.docker.com/r/bitnami/openldap/ docker run -p 1389:1389 --name openldap bitnami/openldap:latest 클라이언트 설치 및 서버 연결 Apache Directory Studio: https://directory.apache.org/studio/downloads.html 따로 설정하지 않고 컨테이너를 실행했다면, 기본 설정값은 admin/adminpassword이다. 참고: https://hub.docker.com/r/bitnami/openldap/ 컨테이너를 실행하면, 자동으로 엔트리도 몇 개 추가된 것을 확인할 수 있다. 엔트리 구성 중 트러블 슈팅 no global superior knowledge dc=com 을 만드려고하니 아래와 같은 오류가 발생했다. 원인을 찾아보니 ldap에는 suffix라는 설정값이 존재한다....
배경 팀 코드에 OpenPerRequestFilter를 상속한 형태의 Filter가 존재했다. 이 클래스는 어떤 역할인지 확인할 필요가 있었다. 필요한 상황 Filter는 서블릿 실행 전과 후에 호출된다. 요청이 서블릿으로 들어오면 서블릿은 다른 서블릿으로 포워딩 할 수도 있다. 이 과정에서 같은 필터를 여러 번 호출할 수도 있다. Spring은 이런 상황에서 필터가 한번만 호출되는 것을 보장시켜주기 위해 OncePerRequestFilter을 제공한다. 사용법 OncePerRequestFilter를 상속한 클래스를 정의하고, doFilterINternal() 메소드를 override하면 된다. public class AuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String usrName = request....
목표 OAuth2.0 이 무엇인지 이해한다. OAuth2.0 의 동작 방식을 이해한다. OAuth2.0 Open Authorization 웹 사이트나 애플리케이션이 다른 웹앱에 호스팅하는 리소스에 접근할 수 있도록 설계된 표준이다. 현재 온라인 인증에 대한 사실상 업계 표준으로 자리 잡고 있다. OAuth2.0 의 구성요소 Resource Owner: 애플리케이션이 자신의 계정에 접근할 수 있도록 권한을 부여하는 사용자 사용자 계정에 대한 접근 권한은 부여된 권한의 scope로 제한된다. Client: 사용자 계정에 액세스하려는 애플리케이션 사용자 계정에 접근하기 위해 Resource Owner의 승인이 필요하다....
Objects.isNull(shortestPath) 로 객체가 null인지 true, false로 반환해준다.
배경 NPE가 발생하고 있는 이슈가 발생해서 로그를 확인하니, 아래와 같이 로그가 남아있고 stack trace가 로깅되어 있지 않았다. java.lang.NullPointerException 원인 JVM에서 최초로 발생하는 예외를 출력하고, 이를 기억해뒀다가 자주 발생하는 것이 확인되면 더 이상 stack trace는 출력하지 하지않도록 최적화가 이루어지고 있다. 이를 기능을 사용하지 않고, 항상 stack trace를 출력하려면 아래와 같이 JVM 옵션을 추가해야된다. -XX:-OmitStackTraceInFastThrow 참고 자료 https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace
아티클 마다 NIC(Network Interface Card)를 설명하는 계층이 달라서 혼란스러웠다. NIC가 어떤 레이어인지 정리해보자. NIC는 1계층이다? 1계층의 목적인 전기신호를 데이터로 변환하는 역할을 NIC가 하고있다. 따라서, NIC는 1계층 장비이다. NIC는 2계층이다? NIC에는 MAC 주소가 있기 때문이다. MAC 주소는 2계층에서 다루어지는 주소다. MAC 주소를 기반으로 전송 받은 데이터를 다음 레이어로 보낼지 말지 선택하기 때문에 2계층이다. 결론 나는 1계층 및 2계층이라고 결론을 지을 것이다. 자료를 검색할수록 각자 다른 결론을 내고 있기 때문에 정답이 없는 문제라고 생각한다....
배경 배포 스크립트를 읽어보는 중 kill -USR1 `cat {nginx pid 파일 경로}` 라는 내용이 있었다. 해당 명령의 의미를 이해해본다. signal 종류 kill 명령어를 통해서 특정 프로세스에 signal을 보낼 수 있다. 그 중 SIGUSR1, SIGUSR2는 커스터마이징이 가능한 signal이다. 참고: https://man7.org/linux/man-pages/man7/signal.7.html pid 파일 nginx는 자신의 pid(프로세스 id)를 파일 형태로 저장해둔다. http://nginx.org/en/docs/ngx_core_module.html#pid 따라서 위 명령어는 nginx 프로세스에 SIGUSR1 signal을 보내는 것이다. Nginx가 SIGUSR1 signal을 받은 경우 Nginx에서는 각 signal에 따른 동작이 미리 정의되어 있다....
HTTP multipart를 이용한 파일 업로드 API를 구현했는데 NGINX에서 거부를 하는 문제가 발생했다. 기본적으로 NGINX의 최대 HTTP body 크기는 1MB다. http { ... client_max_body_size 100M; } 또는 server { ... client_max_body_size 100M; } 와 같은 방법으로 파일 용량 제한을 수정할 수 있다. 참고 자료 https://www.tecmint.com/limit-file-upload-size-in-nginx/ https://stackoverflow.com/questions/26717013/how-to-edit-nginx-conf-to-increase-file-size-upload
Nginx 설치 소스 다운로드 wget http://nginx.org/download/nginx-1.12.2.tar.gz tar xvzf nginx-1.12.2.tar.gz 빌드 cd nginx-1.12.2 ./configure --prefix=/home/{user}/apps/nginx-1.12.2 --user={user} --group={user} --error-log-path=/home/{user}/logs/nginx/error.log --http-log-path=/home/{user}/logs/nginx/access.log --without-http_rewrite_module --without-http_scgi_module --without-http_uwsgi_module --without-http_fastcgi_module make make install 옵션 설명 OS 사용자 -user : OS 사용자 계정. irteam을 권장한다. -group=irteam : OS 사용자의 그룹. irteam을 권장한다. 파일 경로 -prefix : Nginx 빌드 결과물이 들어갈 디렉토리 -error-log-path: 에러 로그를 저장할 경로 -http-log-path : 액세스 로그를 저장할 경로 모듈 선언 -without-http_scgi_module : http_scgi_module 모듈 제외 -without-http_uwsgi_module : http_uwsgi 모듈 제외 -without-http_fastcgi_module : fastcgi_module 모듈 제외 -without-http_rewrite_module : http_rewrite_module 제외 -with-http_ssl_module : HTTPS로 서비스하기 위한 모듈 추가 -with-http_v2_module : HTTP/2로 서비스하기 위한 모듈 추가 그 외 다양한 옵션...
크게 2가지 파일을 만들어줘야된다. 1. Dockefile FROM nginx COPY nginx.conf /etc/nginx/nginx.conf COPY fullchain.pem /etc/letsencrypt/live/hy-notice.kro.kr/fullchain.pem COPY privkey.pem /etc/letsencrypt/live/hy-notice.kro.kr/privkey.pem nginx.conf: nginx의 설정을 저장해두는 파일이다. fullchain.pem, privkey.pem: TLS를 설정하면서 생성한 인증서다. 2. nginx.conf events {} http { upstream app { server 172.17.0.1:8080; } server { listen 80; server_name hy-notice.kro.kr; return 307 https://$host$request_uri; } server { listen 443 ssl; server_name hy-notice.kro.kr; ssl_certificate /etc/letsencrypt/live/hy-notice.kro.kr/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/hy-notice.kro.kr/privkey.pem; # Disable SSL ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 통신과정에서 사용할 암호화 알고리즘 ssl_prefer_server_ciphers on; ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!...
목표 새로 만든 MySQL 서버에 기존에 있던 MySQL 스키마를 그대로 가져오고 싶었다. 해결 방법 mysql에서 제공하는 mysql client에서 db 데이터를 dumping하는 기능을 제공하주고 있다. --no-data는 테이블 내에있는 row 들은 복제하지 않겠다는 옵션이다. mysqldump --user=<username> --host=<hostname> --password --no-data <original db> | mysql -u <user name> -p <new db> mysqldump와 관련된 추가적인 옵션들은 아래 링크에서 확인 가능하다. https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html 참고 자료 https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html https://dev.mysql.com/doc/refman/8.0/en/mysql-batch-commands.html https://www.prisma.io/dataguide/mysql/short-guides/exporting-schemas
배경 객체의 상태를 변화시키면서 같은 메서드를 호출하는 경우 Mockito로 검증하는데 계속 실패했다. class MutableService(val mutableMessageQueue: MutableMessageQueue) { fun run() { val mutable = Mutable() val nextNames = listOf("a", "b", "c", "d") for (nextName in nextNames) { mutable.name = nextName mutableMessageQueue.publish(mutable) } } } class MutableMessageQueue { fun publish(mutable: Mutable?) { if (mutable != null) { println(mutable.name) } } } data class Mutable(var name: String = "") class MutableTest { lateinit var mutableMessageQueue: MutableMessageQueue lateinit var mutableService: MutableService @Test fun test() { // given mutableMessageQueue = mock() mutableService = MutableService(mutableMessageQueue) // when mutableService....
multipart 를 통해 파일을 body로 보내는데, 이미지라서 바이트 데이터로 보내게된다. rest-docs에서는 이를 굳이 보여줄 필요가 없기 때문에, body내용을 바꾸는 기능이 필요했다. 이를 위해서는 preprocessRequest 라는 것을 사용하면 된다. // MockMvc 테스트 중에 .andDo(document("save-image", preprocessRequest(new ImageBodyPreprocessor()), responseFields( fieldWithPath("[]").description("파일 경로")))); public class ImageBodyPreprocessor implements OperationPreprocessor { private static final String FILE = "file"; private static final OperationRequestPartFactory PART_FACTORY = new OperationRequestPartFactory(); private static final OperationRequestFactory REQUEST_FACTORY = new OperationRequestFactory(); @Override public OperationRequest preprocess(final OperationRequest request) { List<OperationRequestPart> parts = new ArrayList<>(); for (OperationRequestPart part : request....
@ExtendWith(MockitoExtension.class) public class BoTest { @Mock private Dao dao; @InjectMocks private Bo bo; @Test public void test() { given(dao.findById(anyLong())) .willReturn(new Object()); } }