자바스프링 개념정리

계층의 종류

  • 프레젠테이션계층(Presenation Layer): 사용자 인터페이스를 담당하는 계층입니다. 웹 어플리케이션에서는 컨트롤러(Controlloer)와 뷰(View)로 구성되며, 사용자 요청을 처리하고, 응답을 생성합니다.
  • 서비스계층(Service Layer): 비즈니스 로직을 처리하는 계층입니다. 프레젠테이션 계층과 데이터엑세스계층(Data Access Layer, 이하 DTA) 사이에서 중간 계층으로 사용되며, 비즈니스 로직을 처리하고 데이터를 가공합니다.
  • 데이터엑세스계층(Data Access Layer): 데이터베이스와의 상호 작용을 담당하는 계층입니다. 데이터베이스와의 CRUD 작업을 수행하기 위해 사용되며, 주로 레포지토리(Repository) 또는 DAO라는 이름으로 구현됩니다.
  • 데이터베이스계층(Database Layer): 데이터를 저장하고 관리하는 계층입니다. 데이터베이스와의 관련된 작업을 수행합니다.
  • 도메인계층(Domain Layer): 도메인 계층은 소프트웨어 시스템에서 가장 핵심적인 계층으로, 비즈니스 로직을 담당하는 계층입니다. 이 계층에서는 사용자가 구체적으로 다루는 데이터와 해당 데이터와 관련된 비즈니스 규칙을 포함하는 도메인 객체를 정의하고, 해당 객체들 간의 상호작용을 구현합니다. 도메인 계층은 시스템 전반에 사용되며, 프렌젠테이션, 서비스, 데이터 엑세스 계층 등 다른 계층과 상호작용할 수 있습니다. 도메인 계층에서는 객체지향 프로그래밍 원칙과 디자인 패턴 등을 활용하여 유지보수성과 확장성이 높은 도메인 객체를 설계하고 구현해야합니다.

DAO(Data Access Object)

데이터베이스에서 데이터를 가져오거나 데이터를 저장하는 등의 CRUD 작업을 수행합니다.

레포지토리(Repository)

데이터베이스와의 상호작용을 담당하는 인터페이스. 레포지토리는 DAO와 동일한 역할을 수행하지만, DAO와 달리 비즈니스 로직을 포함하지 않습니다. 레포지토리는 도메인 클래스를 이용하여 데이터를 처리하며 CRUD 작업을 수행합니다.

도메인클래스(Domain Class)

특정도메인에서 사용되는 데이터를 표현하는 클래스입니다. 도메인 클래스는 업무로직에 밀접하게 관련된 데이터를 다루는데 사용됩니다. 도메인 클래스는 데이터베이스 테이블과 매핑되는 엔티티로 구현될 수 있습니다.

엔티티(Entity)

데이터베이스의 테이블과 매핑되는 클래스입니다. 엔티티는 JPA와 같은 ORM프레임워크를 이용하여 데이터베이스와 상호 작용하며, 도메인 클래스와 유사한 역할을 수행합니다.

DTO(Data Transfer Object)

서로 다른 계층간에 데이터를 전달하기 위한 객체입니다. 보통 클라이언트와 서버 사이, 또는 서비스 계층과 컨트롤러 계층 사이에서 데이터 전송을 위해 사용됩니다. DTO는 특정 계층에서 사용되는 도메인클래스와 달리, 다른 계층 간에 데이터를 전달하기 위한 목적으로 사용됨

VO(Value Object)

소프트웨어에서 사용되는 객체 중 하나로, 값을 저장하는 객체를 의미합니다. 예를 들어, 사용자의 이름, 아이디, 비밀번호 등을 저장하는 객체가 VO입니다. VO는 일반벅으로 불변 객체로 구현됩니다. VO는 DTO와 유사하게 사용되지만, VO는 읽기 전용으로 사용되는 것이 일반적입니다.

vite docker 연결 오류

상황

  • 포트 바인딩 5173:5173
  • npm run dev 실행후 localhost:5173 접속시 ‘localhost에서 연결을 거부했습니다.’ 오류 출력

해결

  • docker inspect에서 port를 보면 0.0.0.0:5173 으로 되어있음
  • vite의 호스트 0.0.0.0 으로으로 지정해줌
//vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server:{
    host: '0.0.0.0',
  }
})

synology VPN 서버 설정

나스설정

  1. 시놀로지 DMS 접속
  2. VPN Server 패키지 설치
  3. VPN server 설정 (프로토콜중 하나만 하나만 사용하는걸 추천)
    1. PPTP
    2. OpenVpn
    3. L2TP/IPSec
      1. 커널 모드에서 실행 체크
      2. 사전 공유키 입력
      3. SHA-256 호환 모드 활성화 끔(96비트)
  4. VPN 서비스관리 > 권한 : 허용할 사용자 권한 추가
  5. 제어판 > 보안 > 방화벽 규칙편집
    1. 내장 응용프로그램 선택항목에서 사용할 VPN의 방화벽 활성화

공유기 설정

  1. 포트포워딩 설정
구분프로토콜로컬포트라우터포트
PPTPTCP17231723
OpenVPNUDP11941194
L2TP/IPSecUDP17011701
L2TP/IPSecUDP500,4500500,4500

맥 VPN 설정

  1. 설정 > 네트워크
  2. L2TP/IPSec 네트워크 생성
    1. 서버주소입력
    2. 계정이름 입력 (VPN 접속 권한을 부여 받은 나스 계정)
    3. 인증 설정
    4. 암호입력 나스 계정 비밀번호
    5. 시스템인증 공유보안 입력: L2TP/IPSec 사전 공유키
    6. 고급설정 > VPN 연결을 통해 모든 트래픽 전송 (미사용시 VPN아이피가 사용되지 않음)

[laravel] 401 unauthorized

오류

  • 자사앱에서 api/user 호출시 401 unauthorized 반환

수정

  • config/sanctum.php 도메인 설정
  • app/Http/Kernel.php
    EnsureFrontendRequestsAreStateful::class 추가
'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

[docker] 도커 사용방법

컨테이너 띄워보기

사용법

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

컨테이너 실행하기

docker run -it -d -p 8080:80 php:8.1-apache

위 명령어를 실행하면 도커는 php:8.1-apache 이미지가 없다면 pull 받아 컨테이너를 실행함

  • -it : -i옵션과 -t옵션을 같이 쓰이는 경우가 많음
    컨테이너를 실행한 후 컨테이너의 쉘이나 cli도구를 사용할때 쓰임
  • -d : 컨테이너를 백그라운드 모드로 실행
  • -p : 포트바인딩 local : containere
  • php:8.1-apache 컨테이너에 사용할 도커이미지
  • docker run | Docker Documentation

생성된 컨테이너 확인

docker ps  

컨테이너 자세히보기

docker inspect <CONTAINER ID>

컨테이너 이미지 빌드하기

  1. Dockerfile 작성
FROM php:8.1-apache
ENV FOO=bar 
WORKDIR /var/www/html
COPY . .
RUN apt-get update && install -y vim
  1. 이미지 빌드하기
    사용법
docker build [OPTIONS] PATH | URL | -

빌드하기

docker build -t myphp .

Dockerfile 수정이 있으면 위 명령어를 통해서 다시 빌드하면 됨

  • -t 이미지 태그 설정

빌드된 이미지 확인

docker image ls
  1. 컨테이너 생성하기
docker run -it -d --name my_php -p 8080:80  myphp
  • --name 옵션이 없는 경우 컨테이너 이름 랜덤 생성됨

컨테이너 터미널접속하기

docker exec -it <CONTAINER ID> /bin/bash

docker volume

컨테이너에서 생성한 파일은 컨테이너를 삭제하게 되면 같이 삭제 되므로 로컬저장소와 컨테이너저장소를 바인딩할 필요가 있다.

볼륨을 관리하는 방법 : Use bind mounts | Docker Documentation

  1. Named vlolumes
    사용법
docker volume create [OPTIONS] [VOLUME]

볼륨생성

docker volume create myVolume

볼륨마운트

docker run -dp 8080:80 -w /var/www/html -v "myVolume:/var/www/html" php:8.1-apache 

불륨정보확인

docker volume inspect myVolume
{
        "CreatedAt": "2021-12-08T14:16:18Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/myVolume/_data",
        "Name": "myVolume",
        "Options": {},
        "Scope": "local"
    }

볼륨정보를 보면 Mountpoint 에 지정된 경로가 컨테이너에 마운트되는 것을 확인 할수 있다.

Ubuntu, centos 환경에서 /var/lib/docker/volumes/ 에 접근할 수있지만 맥환경에서는 해당 경로가 존재하지 않는다.

맥에서 도커는 가상머신을 사용하기 때문이라는것 같은데 Mountpoint 접근 방법과 자세한 내용은 아래 링크를 참조

Mac에서 docker volume 위치

  1. Bind mounts
    불륨생성할 필요 없이 마운트할 경로를 입력해준다.
docker run -dp 8080:80 -w /var/www/html -v "your/path:/var/www/html" php:8.1-apache 

networks

사용법

docker network create [OPTIONS] NETWORK

네트워크생성

docker network create myphp

네트워크를 연결한 Mysql 컨테이너생성

docker run -d \
--network myphp --network-alias mysql \
-v myVolume:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=myphp \
mysql:5.7

mysql 컨테이너 실행

docker exec -it <mysql-container-id> mysql -u root -p

네트워크를 연결한 php컨테이너 mysql 연결하기

 docker run -dp 8080:80 \
   -w /var/www/html -v "$(pwd):/var/www/html" \
   --network myphp \
   -e MYSQL_HOST=mysql \
   -e MYSQL_USER=root \
   -e MYSQL_PASSWORD=secret \
   -e MYSQL_DB=myphp \
   php:8.1-apache 
docker exec -it <myphp-container-id> /bin/bash
  • MYSQL_HOST=mysql : --network-alias 를 mysql 로 지정했기 때문에 호스트를 네트워크별칭으로 넣어줌
dig MYSQL_HOST
; <<>> DiG 9.16.22-Debian <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30839
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;mysql.                IN  A

;; ANSWER SECTION:
mysql.            600 IN  A   172.18.0.2

;; Query time: 1 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Wed Dec 08 15:07:17 UTC 2021
;; MSG SIZE  rcvd: 44

Mysql 컨테이너와 myphp컨테이너에서
dig mysql 명령어를 실행해보면 각각의 컨테이너가 생성한 네크워크를 사용하는 것을 확인 할 수 있다.

myphp 컨테이너에서는 MYSQL_HOST 에 네트워크 별칭을 선언했으므로 dig MYSQL_HOST 으로도 사용 가능하다.

docker compose 사용하기

1개의 서비스에 사용되는 컨테이너가 여러개이고 각각의 옵션이 복잡해진다면 이를 관리하기 힘들어 질것이다.

docker compose 를 사용하면 이러한 문제를 쉽게 해결 할수 있다.

설치확인

docker-compose version

설치문서 : Install Docker Compose | Docker Documentation
맥과 윈도우 환경에서는 별도의 설치가 필요 없다. 만약 docker compose 명령어를 존재하지 않는다는 메시지가 보인다면 루트권한으로 실행하면 된다.

Compose file 생성

  1. 루트 디렉토리에 docker-compose.yml 을 생성해야한다.
  2. 파일을 열고 버전을 명시해준다.
version: "3.7"
  1. 다음으로 사용할 서비스의 목록을 정의한다.
services:

서비스 정의
앞서 네트워스를 설명했던 2개의 커맨드를 docker-compose.yml 에 정의를 할것이다.

우선 두개의 명령어를 가져와 보자면 아래와 같다.
php

 docker run -dp 8080:80 \
   -w /var/www/html -v "$(pwd):/var/www/html" \
   --network myphp \
   -e MYSQL_HOST=mysql \
   -e MYSQL_USER=root \
   -e MYSQL_PASSWORD=secret \
   -e MYSQL_DB=myphp \
   php:8.1-apache 

mysql

docker run -d \
--network myphp --network-alias mysql \
-v myVolume:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=myphp \
mysql:5.7

파일작성하기

version: "3.7"

services:
  myphp:
    build:
      context: . # Dockerfile 경로
    container_name: php-web # 컨테이너 이름
    networks:
      mysql: #network aliase
    ports:
      - 8080:80
      - 8081:443
    volumes:
      - ./web_data:/var/www/html
    environment:
      - MYSQL_HOST=mysql #mysql is network aliase
      - MYSQL_USER=root
      - MYSQL_PASSWORD=secret
      - MYSQL_DB=myphp
  mysql:
    image: mysql:5.7
    container_name: php-mysql
    networks:
      mysql:
    volumes:
      - myVolume:/var/lib/mysql/
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=myphp

volumes:
  myVolume:

networks:
  mysql: #network aliase
    driver: bridge
    name: myphp #netwrok name (docker network ls 로 확인됨)

네트워크대신 link 지정하기
myphp 컨테이너와 mysql 컨테이너는 생성한 mysql 네트워크를 이용해서 서로 접근이 가능하게 처리했다.

이를 좀더 간단하게 처리하려면 컨테이너를 연결하는 link 옵션을 추가하면된다.

version: "3.7"

services:
  myphp:
    build:
      context: . # Dockerfile 경로
    container_name: php-web # 컨테이너 이름
    ports:
      - 8080:80
      - 8081:443
    volumes:
      - ./web_data:/var/www/html
    environment:
      - MYSQL_HOST=mysql #mysql is network aliase
      - MYSQL_USER=root
      - MYSQL_PASSWORD=secret
      - MYSQL_DB=myphp
    links:
      - mysql
  mysql:
    image: mysql:5.7
    container_name: php-mysql
    volumes:
      - myVolume:/var/lib/mysql/
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=myphp

volumes:
  myVolume:

mysql 접속 예제

$host='mysql';
$user='root';
$password='secret';
$dbname='myphp';
$mysqli = new mysqli($host, $user, $password, $dbname);
var_dump($mysqli);
  • $host='mysql'
    • network 를 사용한 경우 컨테이너 아이피 대신 network aliase 를 지정해서 사용할수 있음
    • link를 사용한 경우 컨테이너 아이피 대신 서비스 이름을 지정해서 사용할수 있음

컨테이너 고정아이피 지정하기
컨테이너에 고정아피를 사용해야하는 경우에는 어떻게 할까 ?
네트워크 설정에 ipam 를 정의한 뒤 각 서비스에 고정 아이피를 할당해주면 된다.

version: "3.7"

services:
  myphp:
    build:
      context: . # Dockerfile 경로
    container_name: php-web # 컨테이너 이름
    networks:
      mysql: #network aliase
        ipv4_address: 172.20.0.2
    ports:
      - 8080:80
      - 8081:443
    volumes:
      - ./web_data:/var/www/html
    environment:
      - MYSQL_HOST=mysql #mysql is network aliase
      - MYSQL_USER=root
      - MYSQL_PASSWORD=secret
      - MYSQL_DB=myphp
  mysql:
    image: mysql:5.7
    container_name: php-mysql
    networks:
      mysql:
        ipv4_address: 172.20.0.3
    volumes:
      - myVolume:/var/lib/mysql/
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=myphp

volumes:
  myVolume:

networks:
  mysql: #network aliase
    driver: bridge
    name: myphp #netwrok name (docker network ls 로 확인됨)
    ipam:
      config:
        - subnet: 172.20.0.0/24
          gateway: 172.20.0.1

변수사용하기
루트 디렉토리에 .env을 추가후 변수를 정의하면 docker-compose.yml 에서 사용할수 있다.

도커파일 디렉토리구조

  • project dir
    • Dockerfile
    • docker-compose.yml
    • .env

.env

...
MYSQL_PASSWORD=yourpassword
...

변수의 사용

...
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
...

[php] imagick install

요구사항

ImageMagick 이 설치되어 있어야함

ImageMagick 설치

패키지리스트 업데이트

apt update

ImageMagicK 설치 확인

convert --version

ImageMagicK 및 라이브러리 설치

apt install -y imagemagick libmagickwand-dev libmagickcore-dev

imagick 설치와 모듈 연동

php 모듈 imagick 설치

git clone https://github.com/Imagick/imagick
cd imagick
phpize && ./configure
make
make install

php.ini 모듈 추가
extension=imagick.so

apachectl restart
php -m | grep imagick

[docker] 도커설치 방법

도커설치방법
Ubuntu, Centos, Mac, window 운영체제 별로 설치 법이 있으니 공식 문서를 참조
Install Docker Engine | Docker Documentatio

컨테이너에서 도커를 사용하고 싶을때
ubuntu 환경에서 도커를 설치한 환경을 구성해야 할때 로컬환경이 ubuntu가 아니라면 도커 컨테이너를 통해 환경을 구성할 수 있다.

  • 로컬 도커설치
    • ubuntu 컨테이너 실행
      • 컨테이너에 도커 설치

설치방법은 동일하지만 컨테이너를 실행할때 --privileged 옵션을 통해 권한을 획득한 privileged 모드로 실행 해야한다. 그렇지 않으면 service docker start 명령어를 사용해도 도커가 실행되지 않는다.

Dockerfile 작성
docker-ce 설치시 타임존 선택 옵션이 주어지는데 이미지를 빌드할때 옵션을 선택 할 수 없으므로 타임존을 미리 설정해야 한다.

FROM ubuntu:latest

ENV TZ=Asia/Seoul
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN apt-get update
RUN apt-get install -y \
        ca-certificates \
        curl \
        gnupg \
        lsb-release

RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
RUN echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
      $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

RUN apt-get update
RUN apt-get install -y docker-ce docker-ce-cli containerd.io

이미지 빌드

docker build . -t ubuntu:docker

컨테이너 생성

docker run -it --privileged ubuntu:docker

docker demon 실행

root@~:/# service docker status
 * Docker is not running
root@~:/# service docker start
 * Starting Docker: docker   

[javascript] window.open POST 값 보내기

$(".btn").click(function(){
    var url = 'test.test/test';
    var form = $("form");
    var target = '타이틀 제목';
    window.open(url, target, "width=500,height=500,resizable=yes,toolbar=yes,menubar=yes,location=yes");

    form.attr('action', url);
    form.attr('target', target); // window.open 타이틀과 매칭 되어야함
    form.attr('method', 'post');

    form.append('<input type="text" name="mb_id" value="foo">'); // 동적으로 값을 추가할때
    form.submit();
});