Spring Bootで@ControllerAdviceを使って例外処理を共通化する方法|新人エンジニア向けに解説

こんにちは。ゆうせいです。

今回は、Spring Bootで@ControllerAdviceを使って例外処理を共通化する方法を、新人エンジニア向けに解説します。

Spring BootでController、Service、DAOを書いていると、いろいろな場所で例外が発生します。

ユーザーが見つからない
入力値が不正
DB接続に失敗した
SQLでエラーが出た
想定外のNullPointerExceptionが起きた

このような例外を各Controllerで毎回try-catchすると、コードが重複して読みにくくなります。

そこで使うのが@ControllerAdviceです。

@ControllerAdviceは、複数のControllerにまたがる共通処理をまとめるための仕組みです。Spring Framework公式ドキュメントでも、@ExceptionHandler、@InitBinder、@ModelAttributeを@ControllerAdviceに定義すると、任意のControllerに対して適用できると説明されています。

@ControllerAdviceとは何か

@ControllerAdviceは、Controller全体に対する「共通の助言役」です。

名前にAdvice、つまり「助言」という言葉が入っています。

例外処理で使う場合は、「Controllerで例外が起きたら、このクラスでまとめて処理します」という意味になります。

たとえるなら、学校の各教室でトラブルが起きたときに、担任の先生が毎回バラバラに対応するのではなく、職員室の共通窓口で対応ルールを決めておくようなものです。

やり方特徴
各Controllerでtry-catch同じ処理が何度も出てくる
@ControllerAdviceで共通化例外処理を1か所にまとめられる

なぜ例外処理を共通化するのか

例外処理を共通化する理由は、主に次の3つです。

理由説明
Controllerが読みやすくなる正常処理とエラー処理を分けられる
同じエラー対応を統一できる404、400、500などの返し方をそろえられる
修正しやすくなるエラーメッセージやログ出力を1か所で変更できる

Controllerは、本来「リクエストを受け取り、Serviceを呼び出し、画面やレスポンスを返す」役割に集中させたい場所です。

例外処理をControllerに大量に書くと、本来の処理が見えにくくなります。

料理でたとえるなら、レシピの中に「火災時の避難方法」「停電時の対応」「材料が腐っていた場合の連絡先」まで毎回書いてあるようなものです。

必要な情報ではありますが、全部を毎回レシピに書くと読みにくいですよね。

@ExceptionHandlerとは何か

@ControllerAdviceと一緒によく使うのが@ExceptionHandlerです。

@ExceptionHandlerは、「この例外が起きたら、このメソッドで処理します」という指定です。

Spring Framework公式ドキュメントでは、Spring MVCにおける@ExceptionHandlerメソッドは、DispatcherServletレベルのHandlerExceptionResolverの仕組みに基づいてサポートされていると説明されています。

まず、Controllerの中に直接@ExceptionHandlerを書く例を見てみましょう。

@Controller
public class SampleController {

    @GetMapping("/sample")
    public String sample() {
        throw new IllegalArgumentException("不正な値です。");
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArgumentException() {
        return "error/400";
    }
}




この書き方でも動きます。

しかし、この@ExceptionHandlerは基本的にこのController内の例外処理です。

複数のControllerで同じ例外処理をしたい場合、各Controllerに同じ処理を書くことになります。

そこで@ControllerAdviceへ移動します。

基本形:@ControllerAdviceで例外処理を共通化する

まずは、画面を返すSpring MVC向けの基本形です。

package com.example.demo.exception;

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

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArgumentException() {
        return "error/400";
    }

    @ExceptionHandler(Exception.class)
    public String handleException() {
        return "error/500";
    }
}




このクラスを作ると、どのControllerでIllegalArgumentExceptionが発生しても、error/400.htmlを表示できます。

また、想定外のExceptionが発生した場合は、error/500.htmlを表示します。

例外表示する画面意味
IllegalArgumentExceptionerror/400リクエストや値が不正
Exceptionerror/500想定外のサーバーエラー

エラー画面を作る

Thymeleafを使っている場合、次の場所にエラー画面を作ります。

src/main/resources/templates/error/400.html

400.htmlです。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>入力エラー</title>
</head>
<body>

<h1>入力内容に問題があります</h1>

<p>リクエスト内容を確認してください。</p>

<p>
    <a th:href="@{/}">トップページへ戻る</a>
</p>

</body>
</html>




500.htmlです。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>サーバーエラー</title>
</head>
<body>

<h1>サーバー内部でエラーが発生しました</h1>

<p>時間をおいて再度お試しください。</p>

<p>
    <a th:href="@{/}">トップページへ戻る</a>
</p>

</body>
</html>




このようにしておくと、ユーザーにJavaの例外メッセージを直接見せずに、わかりやすいエラー画面を表示できます。

Controller側はどう書くのか

Controller側では、try-catchを書かずに例外を投げるだけにできます。

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class UserController {

    @GetMapping("/users/detail")
    public String detail(@RequestParam int userId) {

        if (userId <= 0) {
            throw new IllegalArgumentException("userIdは1以上で指定してください。");
        }

        return "users/detail";
    }
}




userIdが0以下の場合、IllegalArgumentExceptionが発生します。

その例外はGlobalExceptionHandlerで処理され、error/400.htmlが表示されます。

Controllerの中にエラー画面を返す処理を書かなくてよいので、コードがすっきりします。

独自例外を作る

実務では、Java標準の例外だけでなく、アプリ専用の例外を作ることがよくあります。

たとえば、ユーザーが見つからない場合の例外です。

package com.example.demo.exception;

public class UserNotFoundException extends RuntimeException {

    public UserNotFoundException(String message) {
        super(message);
    }
}




UserNotFoundExceptionは、「ユーザーが見つからない」という意味を持つ独自例外です。

RuntimeExceptionを継承しています。

RuntimeExceptionは、実行時例外と呼ばれる種類の例外です。

新人エンジニア向けに言うと、「処理中に起きる想定外または業務上の異常」を表すためによく使います。

独自例外をControllerで使う

ControllerでUserNotFoundExceptionを投げてみます。

package com.example.demo.controller;

import com.example.demo.exception.UserNotFoundException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class UserController {

    @GetMapping("/users/detail")
    public String detail(@RequestParam int userId) {

        if (userId == 999) {
            throw new UserNotFoundException("指定されたユーザーが見つかりません。");
        }

        return "users/detail";
    }
}




本来はServiceやDAOでユーザー検索をして、見つからなかった場合に例外を投げることが多いです。

今回はサンプルなので、Controller内で条件を書いています。

独自例外を@ControllerAdviceで処理する

GlobalExceptionHandlerにUserNotFoundException用の処理を追加します。

package com.example.demo.exception;

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

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public String handleUserNotFoundException() {
        return "error/404";
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArgumentException() {
        return "error/400";
    }

    @ExceptionHandler(Exception.class)
    public String handleException() {
        return "error/500";
    }
}




UserNotFoundExceptionが発生した場合、error/404.htmlを表示します。

404は、Not Found、つまり「見つからない」という意味です。

src/main/resources/templates/error/404.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>見つかりません</title>
</head>
<body>

<h1>指定されたデータが見つかりません</h1>

<p>URLや検索条件を確認してください。</p>

<p>
    <a th:href="@{/}">トップページへ戻る</a>
</p>

</body>
</html>




例外HTTP的な意味表示画面
UserNotFoundException404 Not Founderror/404
IllegalArgumentException400 Bad Requesterror/400
Exception500 Internal Server Errorerror/500

Modelにエラーメッセージを渡す

例外メッセージを画面に表示したい場合は、Modelを使えます。

package com.example.demo.exception;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public String handleUserNotFoundException(
            UserNotFoundException e,
            Model model) {

        model.addAttribute("errorMessage", e.getMessage());

        return "error/404";
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArgumentException(
            IllegalArgumentException e,
            Model model) {

        model.addAttribute("errorMessage", e.getMessage());

        return "error/400";
    }

    @ExceptionHandler(Exception.class)
    public String handleException(
            Exception e,
            Model model) {

        model.addAttribute("errorMessage", "予期しないエラーが発生しました。");

        return "error/500";
    }
}




error/404.htmlでは、次のように表示できます。

<p th:text="${errorMessage}"></p>

ただし、500エラーでは、例外の詳細メッセージをそのままユーザーに表示しないほうが安全です。

SQLエラーやファイルパスなど、内部情報が漏れる可能性があるためです。

ユーザー向けにはやさしい文言を表示し、詳細はログに残すのが基本です。

ログを出す

実務では、例外が起きたときにログを出します。

ログとは、システム内で何が起きたかを記録する情報です。

エラー調査では、ログがとても重要です。

package com.example.demo.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger =
            LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(UserNotFoundException.class)
    public String handleUserNotFoundException(
            UserNotFoundException e,
            Model model) {

        logger.warn("ユーザーが見つかりません: {}", e.getMessage());

        model.addAttribute("errorMessage", e.getMessage());

        return "error/404";
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArgumentException(
            IllegalArgumentException e,
            Model model) {

        logger.warn("不正なリクエストです: {}", e.getMessage());

        model.addAttribute("errorMessage", e.getMessage());

        return "error/400";
    }

    @ExceptionHandler(Exception.class)
    public String handleException(
            Exception e,
            Model model) {

        logger.error("予期しないエラーが発生しました。", e);

        model.addAttribute("errorMessage", "予期しないエラーが発生しました。");

        return "error/500";
    }
}




warnは、想定できる注意レベルのログに使います。

errorは、システム的に調査が必要な重大なエラーに使います。

ログレベル使う場面
warnデータなし、不正な入力など、想定できる異常
errorDB障害、NullPointerExceptionなど、調査が必要な異常

例外を握りつぶしてはいけません。

ユーザーには見せない。

でも、開発者が調査できるようにログには残す。

このバランスが大切です。

APIの場合は@RestControllerAdviceを使う

画面ではなくJSONを返すAPIでは、@ControllerAdviceより@RestControllerAdviceを使うことが多いです。

@RestControllerAdviceは、@ControllerAdviceに@ResponseBodyの性質を合わせたようなものです。

つまり、戻り値をビュー名ではなくJSONなどのレスポンス本文として返しやすくなります。

Spring Frameworkの公式ドキュメントでは、@ControllerAdviceや@RestControllerAdviceを使うことで、@ExceptionHandlerなどのメソッドを複数Controllerへ適用できると説明されています。

API用のエラーレスポンスクラス

まず、APIで返すエラー用DTOを作ります。

package com.example.demo.api;

import java.time.LocalDateTime;

public class ApiErrorResponse {

    private int status;
    private String error;
    private String message;
    private LocalDateTime timestamp;

    public ApiErrorResponse(int status, String error, String message) {
        this.status = status;
        this.error = error;
        this.message = message;
        this.timestamp = LocalDateTime.now();
    }

    public int getStatus() {
        return status;
    }

    public String getError() {
        return error;
    }

    public String getMessage() {
        return message;
    }

    public LocalDateTime getTimestamp() {
        return timestamp;
    }
}




APIでは、エラー時にも一定の形でJSONを返すと、フロントエンド側が扱いやすくなります。

{
    "status": 404,
    "error": "Not Found",
    "message": "指定されたユーザーが見つかりません。",
    "timestamp": "2026-06-18T10:00:00"
}

このように形を統一しておくと、JavaScript側でメッセージを表示しやすくなります。

@RestControllerAdviceのサンプル

package com.example.demo.api;

import com.example.demo.exception.UserNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ApiExceptionHandler {

    private static final Logger logger =
            LoggerFactory.getLogger(ApiExceptionHandler.class);

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ApiErrorResponse> handleUserNotFoundException(
            UserNotFoundException e) {

        logger.warn("APIでユーザーが見つかりません: {}", e.getMessage());

        ApiErrorResponse response =
                new ApiErrorResponse(
                        404,
                        "Not Found",
                        e.getMessage()
                );

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ApiErrorResponse> handleIllegalArgumentException(
            IllegalArgumentException e) {

        logger.warn("APIで不正なリクエストです: {}", e.getMessage());

        ApiErrorResponse response =
                new ApiErrorResponse(
                        400,
                        "Bad Request",
                        e.getMessage()
                );

        return ResponseEntity.badRequest().body(response);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiErrorResponse> handleException(Exception e) {

        logger.error("APIで予期しないエラーが発生しました。", e);

        ApiErrorResponse response =
                new ApiErrorResponse(
                        500,
                        "Internal Server Error",
                        "サーバー内部でエラーが発生しました。"
                );

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




このようにすると、APIで例外が発生したときに、JSON形式でエラーを返せます。

画面を返すWebアプリでは@ControllerAdvice。

JSONを返すAPIでは@RestControllerAdvice。

まずはこの使い分けを覚えてください。

用途使うアノテーション戻り値の例
Thymeleaf画面@ControllerAdviceerror/404などのビュー名
REST API@RestControllerAdviceResponseEntityやDTO

ControllerでAPI例外を投げる

API用Controllerの例です。

package com.example.demo.api;

import com.example.demo.exception.UserNotFoundException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserApiController {

    @GetMapping("/api/users/{userId}")
    public String findUser(@PathVariable int userId) {

        if (userId == 999) {
            throw new UserNotFoundException("指定されたユーザーが見つかりません。");
        }

        if (userId <= 0) {
            throw new IllegalArgumentException("userIdは1以上で指定してください。");
        }

        return "ユーザー情報です。";
    }
}




/api/users/999にアクセスすると、UserNotFoundExceptionが発生します。

ApiExceptionHandlerが処理し、404のJSONを返します。

/api/users/0にアクセスすると、IllegalArgumentExceptionが発生します。

ApiExceptionHandlerが処理し、400のJSONを返します。

例外とHTTPステータスの対応

例外処理では、どの例外をどのHTTPステータスに対応させるかが大切です。

状況例外例HTTPステータス
入力値が不正IllegalArgumentException400 Bad Request
データが存在しないUserNotFoundException404 Not Found
権限がないAccessDeniedExceptionなど403 Forbidden
ログインしていないAuthenticationExceptionなど401 Unauthorized
想定外のエラーException500 Internal Server Error

全部を500にすると、ユーザーやAPI利用者が「自分の入力が悪いのか、サーバーが悪いのか」を判断できません。

ステータスコードは、システム同士の会話です。

正しく使うことで、エラー対応がしやすくなります。

Exceptionを最後に書く理由

@ExceptionHandler(Exception.class)は、ほぼすべての例外を受け取れる大きな網です。

そのため、個別の例外処理を先に用意し、最後の保険としてExceptionを置くのが基本です。

@ExceptionHandler(UserNotFoundException.class)
public String handleUserNotFoundException() {
    return "error/404";
}

@ExceptionHandler(IllegalArgumentException.class)
public String handleIllegalArgumentException() {
    return "error/400";
}

@ExceptionHandler(Exception.class)
public String handleException() {
    return "error/500";
}




たとえるなら、小さな魚は専用の水槽へ、大きく分類できない魚は最後に大きな水槽へ入れるようなものです。

最初から全部を大きな水槽へ入れると、種類ごとの対応ができません。

やってはいけない例外処理

新人エンジニアがやりがちな危険な例外処理を整理します。

悪い例なぜよくないか
catchして何もしないエラー原因が消えて調査できない
全部RuntimeExceptionに包むだけ何が起きたかわかりにくい
ユーザーに例外詳細をそのまま表示するSQLや内部構造が漏れる危険がある
全部500で返す入力ミスとサーバー障害を区別できない
Controllerごとに同じtry-catchを書く重複が増えて保守しにくい

特に、catchして何もしない処理は避けてください。

try {
    userService.register();
} catch (Exception e) {
}




このコードは、エラーを握りつぶしています。

火災報知器が鳴ったのに、音がうるさいから電源を切るようなものです。

エラーは消えたように見えますが、問題は残っています。

ServiceやDAOではどうするのか

ServiceやDAOでは、異常が起きたら意味のある例外を投げます。

DAOの例です。

package com.example.demo.model.dao;

import com.example.demo.exception.UserNotFoundException;
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    public String findUserNameById(int userId) {

        if (userId == 999) {
            throw new UserNotFoundException("userId=" + userId + " のユーザーが見つかりません。");
        }

        return "山田太郎";
    }
}




Serviceの例です。

package com.example.demo.service;

import com.example.demo.model.dao.UserDao;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public String findUserName(int userId) {

        if (userId <= 0) {
            throw new IllegalArgumentException("userIdは1以上で指定してください。");
        }

        return userDao.findUserNameById(userId);
    }
}




Controllerの例です。

package com.example.demo.controller;

import com.example.demo.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/users/detail")
    public String detail(@RequestParam int userId, Model model) {

        String userName = userService.findUserName(userId);

        model.addAttribute("userName", userName);

        return "users/detail";
    }
}




Controllerにはtry-catchがありません。

ServiceやDAOで例外が発生した場合、@ControllerAdviceが共通処理として受け取ります。

この流れがわかると、例外処理の役割分担がかなり理解しやすくなります。

@ControllerAdviceが向いている処理

向いている処理理由
共通エラー画面の表示Controllerごとの重複を減らせる
APIエラー形式の統一JSONの形をそろえられる
ログ出力例外発生時の記録を一元化できる
独自例外の変換業務例外をHTTPステータスへ対応づけられる

@ControllerAdviceに向いていない処理

向いていない処理理由
通常の入力チェック@ValidとBindingResultで扱うほうが自然
業務ロジックの分岐Serviceで判断すべき
正常系の画面遷移Controllerの役割
DB更新処理DAOやRepositoryの役割

@ControllerAdviceは便利ですが、何でも入れる場所ではありません。

例外処理の共通窓口として使いましょう。

@ValidとBindingResultとの違い

入力チェックでは、@ValidとBindingResultを使うことも多いです。

@ControllerAdviceとは役割が違います。

仕組み主な用途
@Valid + BindingResultフォーム入力の通常チェック名前未入力、メール形式不正
@ControllerAdvice例外になった異常の共通処理データなし、想定外エラー、DB障害

ユーザーが入力欄を空にしただけなら、基本的には@ValidとBindingResultで画面に戻します。

一方、ServiceやDAOで例外が発生した場合は@ControllerAdviceで処理します。

つまり、@Validは「入力フォームのチェック係」、@ControllerAdviceは「例外発生時の共通窓口」です。

新人エンジニア向けの最小構成

最初は、次の3つだけ覚えれば十分です。

package com.example.demo.exception;

public class UserNotFoundException extends RuntimeException {

    public UserNotFoundException(String message) {
        super(message);
    }
}

package com.example.demo.exception;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public String handleUserNotFoundException(
            UserNotFoundException e,
            Model model) {

        model.addAttribute("errorMessage", e.getMessage());

        return "error/404";
    }

    @ExceptionHandler(Exception.class)
    public String handleException(Model model) {

        model.addAttribute("errorMessage", "予期しないエラーが発生しました。");

        return "error/500";
    }
}

if (user == null) {
    throw new UserNotFoundException("指定されたユーザーが見つかりません。");
}


まずは、独自例外を作る。

@ControllerAdviceで受け取る。

エラー画面を返す。

この3ステップを手で動かして確認してください。

まとめ

@ControllerAdviceは、Spring Bootで例外処理を共通化するための便利な仕組みです。

Controllerごとにtry-catchを書くのではなく、例外処理を1つのクラスにまとめることで、コードが読みやすくなり、エラー対応も統一できます。

用語意味
@ControllerAdvice複数Controllerにまたがる共通処理を定義する
@ExceptionHandler特定の例外が起きたときの処理を書く
@RestControllerAdviceAPI向けにJSONなどを返す共通例外処理を定義する
独自例外アプリ独自の異常を表す例外クラス
ResponseEntityAPIでHTTPステータスとレスポンス本文を返すためによく使う

一言でまとめるなら、@ControllerAdviceは「Controller全体の例外処理をまとめる職員室」です。

各Controllerで同じtry-catchを書くのではなく、共通の例外処理クラスに任せましょう。

新人エンジニアは、まず次の流れを覚えてください。

ServiceやDAOで異常が起きる
        ↓
意味のある例外をthrowする
        ↓
@ControllerAdviceが受け取る
        ↓
@ExceptionHandlerで例外ごとに処理する
        ↓
画面またはJSONを返す

今後の学習では、@ExceptionHandler、@ControllerAdvice、@RestControllerAdvice、ResponseEntity、独自例外、HTTPステータス、ログ出力、@ValidとBindingResultの違いを順番に学ぶとよいです。まずは、404用の独自例外と500用の共通エラー画面を作り、小さなSpring Bootアプリで動きを確認してみましょう!

セイ・コンサルティング・グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。