반응형

 

 

https://aws.amazon.com/ko/lightsail/ 

 

가상 프라이빗 서버 및 웹 호스팅–Amazon Lightsail—Amazon Web Services

WordPress, Magento, Prestashop, Joomla와 같은 사전 구성된 애플리케이션을 통해 단 몇 번의 클릭으로 블로그, 전자 상거래 또는 개인 웹 사이트를 구축합니다.

aws.amazon.com

여기서 lightsail 시작하기를 합니다. 

여기서 create instance 를 통해 서버 (instance) 를 생성합니다.

region 은 서울로 해주세요. 가까운 위치의 서버가 더 빠릅니다. 외국 서비스가 아니라면

워드프레스 일반이 일반적인데, 저는 처음이지만 꿈과 욕심이 커서 multisite 로 하겠습니다.

multisite 가 하나의 인스턴스로 여러 워드프레스를 관리하는 플랫폼이여서요.

처음 테스트 버젼이라면 512MB 를 써도 되겠지만, 저는 메모리 2GB 로 하겠습니다. 
첫 3달이 프리인건 똑같고, 제 기준 서비스 최소 단위가 2GB 라고 생각해서요. 
처음 시작용이라고 보면 512MB 로 맛보기도 좋을 것 같습니다. 

이렇게 하고 생성 요청하면


인스턴스(서버)가 생성되었습니다.

러닝이여도 바로 서버가 시작되지 않고, 실행되는데 일정시간 소요 되는 것 같습니다. 5분만 기다려주세요. 

서버의 manage 를 눌러 해당 서버의 [connect using SSH] 를 합니다,
그럼 서버의 터미널에 접속하게 됩니다.

여기서 콘솔에 

cat $HOME/bitnami_application_password

를 입력해주면 암호가 나옵니다. 추후 WordPress 웹사이트 관리 대시보드에 로그인하는데 사용합니다.

여기서 나온 암호로

이렇게 로그인합니다. 
로그인 하는 서버 주소는 

http://PublicIpAddress/wp-login.php

public ip 는 서버생성하면 화면에 보입니다.


이렇게 로그인 하면 아래와 같이 어드민 대시보드가 나옵니다.



그리고 다시 서버에서 static ip 정적ip 를 세팅해줍니다.

왜냐하면 서버를 리부팅 하거나 서버가 다운되었다가 다시 시작되면 ip 가 바뀌고 그럼 도메인에 연결해줫던 ip 를 또 바꿔줘야 해서 번거롭습니다. 그리고 마침 lightsail 은 정적ip 가 무료인거 같습니다.



그리고 dns 서버를 어떤걸 쓰든 해당 도메인에 생성된 정적 ip 를 연결해줍니다.
저는 namecheap 에서 도메인을 사서

A Record 로 ip 주소를 적었습니다. 앞에 host 칸은 도메인 명의 prefix 설정입니다.
예를 들어 제 도메인이 mj-house.co 인데 하나 도메인에 여러개 도메인을 사용하고 싶어 
event.mj-house.co 로 요청오면 value 에 써져있는 ip 로 이동시키라는 이야기 입니다.

ip 를 연결해주면 이제 워드프레스에서 도메인 세팅 및 https 인증만 받으면 끝납니다.

워드프레스 도메인 세팅 
도메인 세팅 명령어

sudo /opt/bitnami/configure_app_domain --domain <domain>

EX) event.mj-house.co

여기까지 하면 도메인으로 접속시 


다음과 같이 인증이 안되어 있을 겁니다.
이 떄 워드프레스 서버 내부에서 인증서를 설치해주면 됩니다. 

sudo /opt/bitnami/bncert-tool

위 코드를 터미널에 사용하여 

다음처럼 domain list 에 도메인을 등록해주고, lightsail 에서 인스턴스를 한번 재시작해주면 됩니다.
재시작안하면 적용이 안되는거 같더라고요. 
bncert 도구로 워드프레스 인증받으시면 됩니다.





lightsail 워드프레스 멀티사이트 시작하는 가이드입니다. 
https://lightsail.aws.amazon.com/ls/docs/en_us/articles/amazon-lightsail-quick-start-guide-wordpress-multisite 

lightsail 워드프레스 한글 튜토리얼
https://lightsail.aws.amazon.com/ls/docs/ko_kr/articles/amazon-lightsail-tutorial-launching-and-configuring-wordpress

도메인 세팅 
https://lightsail.aws.amazon.com/ls/docs/en_us/articles/amazon-lightsail-define-the-primary-domain-for-your-wordpress-multisite 

https 인증 
https://lightsail.aws.amazon.com/ls/docs/ko_kr/articles/amazon-lightsail-enabling-https-on-wordpress 

반응형
반응형

excel poi 라이브러리

 <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>

spring webflux 에서는 HttpServletResponse 를 사용하지 않아 header 에 xlsx 정보를 넣어주는부분에서 spring 일반 샘플대로 하면 오류가 생길 것이다. 
HttpHeaders 에 set 해주고 Mono.just 에 headers 를 세팅해주면 된다. 

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import reactor.core.publisher.Mono;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@RestController
public class ExcelController {

    @GetMapping("/download-excel")
    public Mono<ResponseEntity<ByteArrayResource>> downloadExcel() {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");

        // Create some sample data
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Name");
        headerRow.createCell(1).setCellValue("Email");

        Row dataRow = sheet.createRow(1);
        dataRow.createCell(0).setCellValue("John Doe");
        dataRow.createCell(1).setCellValue("john.doe@example.com");

        // Generate Excel file bytes
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            workbook.write(outputStream);
            workbook.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Set up the HTTP response headers
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", "data.xlsx");

        // Create a ByteArrayResource from the file bytes
        ByteArrayResource resource = new ByteArrayResource(outputStream.toByteArray());

        // Return the response entity with the file bytes and headers
        return Mono.just(ResponseEntity.ok()
                .headers(headers)
                .contentLength(outputStream.size())
                .body(resource));
    }
}

 

반응형
반응형

필요한 라이브러리

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
    <groupId>io.asyncer</groupId>
    <artifactId>r2dbc-mysql</artifactId>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

 

 

설정 코드 

@Configuration
@EnableR2dbcRepositories
public class R2DBCConfiguration extends AbstractR2dbcConfiguration {
    @Override
    @Bean
    public ConnectionFactory connectionFactory() {
        ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
                        .option(DRIVER, "mysql")
                        .option(HOST, "localhost")
                        .option(USER, "root")
                        .option(PASSWORD, "password")
                        .option(PORT, 3307)
                        .option(DATABASE, "db")
                                                    .build());
        return connectionFactory;
    }
}

와 같이 설정하면 db 연결된다.

세팅 및 설정 관련 문서

https://github.com/asyncer-io/r2dbc-mysql

반응형
반응형

Axios 모듈 패키지 추가/설치

패키지에 axios 패키지 추가해서 쓸 수 있다.

 

$ yarn add axios
or 
$ npm install axios --save

 

Boot File 에 추가하기

 

quasar new boot axios

명령어를 입력하면 src/boot 폴더에 axios.js 파일이 생긴다. 

여기에 

import { boot } from 'quasar/wrappers'
import axios from 'axios'

const api = axios.create({ baseURL: 'https://api.example.com' })

export default boot(({ app }) => {
  // for use inside Vue files (Options API) through this.$axios and this.$api

  app.config.globalProperties.$axios = axios
  // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
  //       so you won't necessarily have to import axios in each vue file

  app.config.globalProperties.$api = api
  // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
  //       so you can easily perform requests against your app's API
})

export { axios, api }

다음과 같이 axios 모듈을 추가해 준다.

반응형
반응형

webflux 를 사용하면 spring boot 내장서버가 tomcat 에서 netty 로 사용해야 하는데,

netty 가 비동기에 유리한 서버이다 보니, sleep 을 주고 싶은 로직이 있을 떄 sleep 을 주기가 비효율적이다

 

 

Spring Netty를 사용할 때 Thread.sleep()를 사용하여 지정된 시간 동안 스레드 실행을 일시 중지 할 수 있다 .

하지만 이벤트 루프를 차단하고 성능 문제를 일으킬 수 있으므로 Netty 애플리케이션에서 와 같은 차단 작업을 사용하는 것은 일반적으로 권장되지 않는다 .

 

대신 Netty는 패키지 에서 사용할 수 있는 ScheduledExecutorService를 사용하여 작업 지연을 위한 비동기 대안을 제공한다 io.netty.util. schedule()의 방법을 사용하여 ScheduledExecutorService지정된 지연 후 작업 실행을 예약 할 수 있습니다 .

ScheduledExecutorService 다음은 Spring Netty 애플리케이션에서 어떻게 사용할 수 있는지에 대한 예입니다

 

 

spring netty 에서 ScheduledExecutorService를 사용한 예시다.

EventLoopGroup클래스에 빈을 주입합니다 .

@Autowired
private EventLoopGroup eventLoopGroup;
 

ScheduledExecutorService지연이 있는 작업을 예약하려면 다음을 사용

 
eventLoopGroup.schedule(() -> {
    // Code to be executed after the delay
}, 500, TimeUnit.MILLISECONDS);

 

 

이 예에서 작업은 500밀리초 지연 후에 실행됩니다. 필요에 따라 지연 및 시간 단위를 조정할 수 있다.

Netty에서 제공하 ScheduledExecutorService를 사용하면 이벤트 루프를 지연시키지 않으므로 애플리케이션이 응답성과 성능을 유지할 수 있습니다.

참고: Spring Netty 애플리케이션에서 Thread.sleep()를 사용해야 하는 경우 이벤트 루프 차단을 피하기 위해 별도의 스레드에서 사용할 수 있습니다. 그러나 일반적으로 가능할 때마다 Netty에서 제공하는 비동기 메커니즘을 활용하는 것이 좋다.

 

ScheduledExecutorService는 특정 시간 또는 간격으로 작업을 예약하고 실행하는 편리한 방법을 제공하므로 주기적 또는 지연된 작업을 수행해야 하는 시나리오에 유용.
비동기 이벤트 기반 네트워크 애플리케이션 프레임워크인 Netty는 ScheduledExecutorService를 활용하여 비차단 방식으로 지연된 작업을 처리한다. 애플리케이션의 실행 및 성능을 차단하지 않고 이벤트 루프에서 작업을 예약할 수 있다.

 

 

 

반응형
반응형

@ExceptionHandler

@ExceptionHandler  @Controller , @RestController 가 적용된 Bean 에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능이다. @ExceptionHandler 에 설정한 예외가 발생하면 handler가 실행된다. 

 

@RestController
public class MyRestController {
    ...
    ...
    @ExceptionHandler(NullPointerException.class)
    public Object nullex(Exception e) {
        System.err.println(e.getClass());
        return "myService";
    }
}

위와 같이 적용하기만 하면 된다. @ExceptionHandler라는 어노테이션을 쓰고 인자로 캐치하고 싶은 예외클래스를 등록해주면 끝난다.

→ @ExceptionHandler({ Exception1.class, Exception2.class}) 이런식으로 두 개 이상 등록도 가능하다.

위의 예제에서 처럼하면 MyRestController에 해당하는 Bean에서 NullPointerException이 발생한다면, @ExceptionHandler(NullPointerException.class)가 적용된 메서드가 호출될 것이다.

 

주의사항/알아 둘 것

  • Controller, RestController에만 적용가능하다. (@Service같은 빈에서는 안됨.)
  • 리턴 타입은 자유롭게 해도 된다. (Controller내부에 있는 메서드들은 여러 타입의 response를 할 것이다. 해당 타입과 전혀다른 리턴 타입이어도 상관없다.)
  • @ExceptionHandler를 등록한 Controller에만 적용된다. 다른 Controller에서 NullPointerException이 발생하더라도 예외를 처리할 수 없다. -> controllerAdvice 와 같이 사용하면 됨.
  • 메서드의 파라미터로 Exception을 받아왔는데 이것 또한 자유롭게 받아와도 된다.

 

 

@ControllerAdvice

@ExceptionHandler가 하나의 클래스에 대한 것이라면, @ControllerAdvice는 모든 @Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation이다.

 

@RestControllerAdvice
public class MyAdvice {
    @ExceptionHandler(CustomException.class)
    public String custom() {
        return "hello custom";
    }
}

 

종합적으로 @ExceptionHandler 와 @ControllerAdvice 같이 사용하여야 한다.

@RestControllerAdvice
@RequiredArgsConstructor
public class CommonExceptionAdvice {

    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> runtimeException(Exception e) {
        ErrorResponse errorResponse = new ErrorResponse(CustomExceptionCode.ERROR_500);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(errorResponse);
    }

    @ExceptionHandler(CustomException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> customException(Exception e) {
        ErrorResponse errorResponse = new ErrorResponse(CustomExceptionCode.ERROR_500);

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(errorResponse);
    }
 }

위와 같이 특정 Exception 에 대해 응답 코드를 달리해서 처리하면 좋다.

ControllerAdvice 와 같이 사용하면 sevice 레벨에서 예외가 발생해도 handler 에 동작한다.

반응형
반응형

 

1. 왜 이 책을 선택하였나?

현업 7년차 개발자로 스프링 및 개발에 처음 입문하는 누군가에게 추천해줄 책을 찾고 있었다.

그러던 중 이 책이 예제를 통해 간단하게 스프링 입문하기 좋다는 느낌을 받았다. 일단 예제소스의 복잡도가 깊지 않고 간결해서 좋다. 

또한 1,2 장을 통하여 스프링에 처음 입문하는 사람들이 세팅할 수 있게 정리가 되어 있다.

그 이후의 장들은 간단하게 쇼핑몰을 구축해가면서 한단계씩 순차적으로 스프링에서 제공하는 많은 기능을 자유롭게 확장해 사용할 수 있으며 영역별로 개발할 수 있다는 장점이 있다.

 

또한, MultipartFile, RESTful 웹 서비스, 스프링 웹 플로우, 스프링 시큐리티, Log4j 등을 사용하기 때문에 다양한 스프링 기능도 함께 익힐 수 있다. 책을 따라 실습하다 보면 스프링 MVC의 개념과 원리를 자연스레 익힐 수 있을 것이다. 스프링 MVC가 처음이거나 스프링 MVC로 직접 웹 애플리케이션을 만들어 보고 싶은 분에게 추천한다.

 

 

2. 소개

1 - 스프링 과 스프링 MVC 개요

2 - 스프링 개발 환경 설정

3 - 프로젝트 만들기 기본구성

4 - 공통 구조 만들기

5 - 목록 조회 하기 만들기

6 - 다양한 내용의 요청 처리 방식

7 - 데이터 등록 구현

8 - 스프링 시큐리티, 로그인, 로그아웃 처리

9 - 파일 업로드

10 - 예외처리

11 - 로그 방식

12 - 다국어 처리

13- 유효성 검사

14 - RESTful 웹 서비스 개요

15 - 데이터베이스 연동

 

 

3. 아쉬운점 

요즘같이 마이크로서비스가 주목받는 시기에 스프링 기본서를 처음부터 끝까지 다 리딩할 수 있는 분이 있을까 싶긴하다. 

스프링 부트 및 rest api 로만 업무를 처리할 사람에게는 굳이 필요없는 jsp 등의 화면 코드도 작성해야 한다.

 

코드 : https://github.com/gilbutITbook/080266

반응형
반응형

특정 Exception이 발생했을 경우 일정 횟수만큼 재시도할 수 있는 어노테이션이다.

 

예를 들어, 서비스 내에서 다른 서비스에 있는 API를 호출할 때 간헐적으로 통신 오류가 발생할 수 있다.

이럴 때 특정메소드에 재시도 할 수 있는 기능이 있다.

 

사용법은 아주 간단하다.

1. Spring Application에 @EnableRetry 어노테이션 추가

2. 재시도 하고 싶은 메소드에 @Retryable 어노테이션 추가

- include : 여기에 설정된 특정 Exception이 발생했을 경우 retry한다.

- exclude : 설정된 Exception 재시도 제외

- maxAttempts : 최대 재시도 횟수 (기본 3회)

- backoff : 재시도 pause 시간

 

@Retryable(maxAttempts = 2, backoff = @Backoff(2000), value = IllegalStateException.class,
            exclude = { NullPointerException.class, NullPointerException.class })
    public String retryExample(Integer intValue) {
        ~~~~~~~
        return String.format("성공");
    }
반응형

+ Recent posts