Chapter 36

Serviceクラス

kazpgm
kazpgm
2022.01.11に更新

自動作成されたServiceクラスを説明する。

商品情報Serviceクラス(ShohinService.java)

service.ShohinService.java
商品情報ServiceImplクラス(ShohinServiceImpl.java)参照

商品情報ServiceImplクラス(ShohinServiceImpl.java)

service.impl.ShohinServiceImpl.java

package com.kaz01u.demo.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

・Valid:データチェック処理に@Validを付ける。具体的には、registerForShohinUpCsvDoメソッドで商品情報アップロードデータのチェックに使用している。
・実際@Validを動かすにはShohinServiceImplに@Validatedを付ける必要があります。これがないと、@Validは無視されます。

import javax.validation.Valid;

・Autowired:@Autowiredアノテーションで、プロパティ、関数、サービスなどを注入している。

import org.springframework.beans.factory.annotation.Autowired;

・Page:情報一覧ページングのための、情報一覧データとPageableを含んだオブジェクト。

import org.springframework.data.domain.Page;

・Pageable:情報一覧ページングのためページング情報

import org.springframework.data.domain.Pageable;

・MailSender:メール送信

import org.springframework.mail.MailSender;

・SimpleMailMessage:メールメッセージ。From,To,subject、textプロパティなどを保持する。

import org.springframework.mail.SimpleMailMessage;

・Service:サービスクラスには@Serviceを付ける。

import org.springframework.stereotype.Service;

・Transactional:トランザクション処理には@Transactionalを付ける。

import org.springframework.transaction.annotation.Transactional;

・ObjectUtils:空チェックにisEmptyメソッドを使用している。

import org.springframework.util.ObjectUtils;

・Validated:ShohinServiceImplに@Validatedを付けて、registerForShohinUpCsvDoメソッドで商品情報アップロードデータに@Validを付けることにより、Validチェックを行います。結果エラー時、ConstraintViolationExceptionが発生し、エラーメッセージがセットされます。

import org.springframework.validation.annotation.Validated;

・Context:テンプレートに埋め込むためのコンテキスト変数に使う。

import org.thymeleaf.context.Context;

・SpringTemplateEngine:テンプレートエンジン。具体的にはsendメソッドでメール本文を作成するのに使用している。

import org.thymeleaf.spring5.SpringTemplateEngine;

・Shohin:商品情報entity

import com.kaz01u.demo.entity.Shohin;

・UploadComplexValidException:CSVファイルアップロード時の複合項目チェック例外クラス

import com.kaz01u.demo.exception.UploadComplexValidException;

・ShohinForm:商品情報のFormクラス

import com.kaz01u.demo.form.ShohinForm;

・ShohinRepository:商品情報のRepositoryクラス

import com.kaz01u.demo.repository.ShohinRepository;

・ShohinService:商品情報サービスクラス

import com.kaz01u.demo.service.ShohinService;

・ShohinUpload:商品情報のCSVアプロードデータクラス

import com.kaz01u.demo.upload.ShohinUpload;

・BiztypeRepository:業種情報のRepositoryクラス

import com.kaz01u.demo.repository.BiztypeRepository;

・CategoryRepository:大分類情報のRepositoryクラス

import com.kaz01u.demo.repository.CategoryRepository;

・SubcategoryRepository:中分類情報のRepositoryクラス

import com.kaz01u.demo.repository.SubcategoryRepository;

・ExtracategoryRepository:小分類情報のRepositoryクラス

import com.kaz01u.demo.repository.ExtracategoryRepository;

・DbElementsService:DBエレメントサービスクラス

import com.kaz01u.demo.service.DbElementsService;

・SeqService:シーケンス作成サービスクラス

import com.kaz01u.demo.service.SeqService;

・Consts:Controller、Serviceに共通するコンストを定義するユーティリティクラス
・現在、コンスト値は1件もありません

import com.kaz01u.demo.utils.Consts;

・Functions:共通関数ユーティリティクラス

import com.kaz01u.demo.utils.Functions;

・RequiredArgsConstructor:初期化が必要なフィールド(finalフィールドなど)の初期化パラメータを引数に持つコンストラクタを生成するためのアノテーション。

import lombok.RequiredArgsConstructor;

・Slf4j:SLF4Jでログ出力する。pom.xmlで指定した、spring-boot-starter-webがlogbackに依存しているので、実装はlogbackです。

import lombok.extern.slf4j.Slf4j;

・ShohinServiceImplに@Validatedを付けて、registerForShohinUpCsvDoメソッドで商品情報アップロードデータに@Validを付けることにより、Validチェックを行います。結果エラー時、ConstraintViolationExceptionが発生し、エラーメッセージがセットされます。

@Validated

・@Serviceアノテーションを記述することで、Spring Boot はService として認識します。

@Service

・@Slf4jアノテーションを記述することで、log という名前でロガーを使用できるようになります。

@Slf4j

・RequiredArgsConstructorアノテーションはfinalフィールドに対してインスタンスを挿入してくれます。(@Autowiredで書かなくてもいい)つまり、以下のshohinRepository~extracategoryRepositoryは@Autowired書かなくてもインジェクションしてくれる。

@RequiredArgsConstructor
public class ShohinServiceImpl implements ShohinService, Consts {
    private final ShohinRepository shohinRepository;
    private final BiztypeRepository biztypeRepository;
    private final CategoryRepository categoryRepository;
    private final SubcategoryRepository subcategoryRepository;
    private final ExtracategoryRepository extracategoryRepository;

・主キーをシーケンスとしたときのキーのサイズを設定する。
・seqService.getDbSeqメソッドでシーケンスキーを作成する時使用する。

    /**
     * Shohinのproducts項目のsizeを指定
     */
    public static final int shohinProductsLen = 10;

・@Autowiredで、各クラスをnewしてインスタンス化(Singleton)してくれる。

    @Autowired
    SeqService seqService;
    @Autowired
    Functions functions;
    @Autowired
    DbElementsService dbElementsService;
    @Autowired
    MailSender mailSender;
    @Autowired
    private SpringTemplateEngine springTemplateEngine;

・@Transactional(readOnly=true)で読み取り専用のトランザクションにする。
・shohinRepository.findAllByOrderByProductsAsc()により、商品情報全件を商品CD昇順で読み込む。

    /**
     * findAllメソッド
     * 商品情報を全件検索する
     */
    @Transactional(readOnly = true)
    @Override
    public List<Shohin> findAll() {
        return shohinRepository.findAllByOrderByProductsAsc();
    }

・@Transactional(readOnly=true)で読み取り専用のトランザクションにする
・商品情報を、条件及び、ページング情報により検索し、Page<Shohin> を戻す。

    /**
     * getFindsShohinメソッド
     * 商品情報を、条件及び、ページング情報により検索する
     */
    @Transactional(readOnly = true)
    @SuppressWarnings("unchecked")
    @Override
    public Page<Shohin> getFindsShohin(String countSql,String selectSql, List<Object> argsList, Pageable pageable) {
        return shohinRepository.finds(countSql, selectSql, argsList, pageable);
    }

・@Transactional(readOnly=true)で読み取り専用のトランザクションにする
・商品情報を、条件により検索し、List<Shohin> を戻す。

    /**
     * getFindsShohinメソッド
     * 商品情報を、条件により検索する
     */
    @Transactional(readOnly = true)
    @SuppressWarnings("unchecked")
    @Override
    public List<Shohin> getFindsShohin(String selectSql, List<Object> argsList) {
        return shohinRepository.finds(selectSql, argsList);
    }

・@Transactional((rollbackFor=Throwable.class)で登録更新でき、Throwable発生の時ロールバックするトランザクションにする

    /**
     * registerメソッド
     * 商品情報を登録する
     */
    @Transactional(rollbackFor=Throwable.class)
    @Override
    public void register(String products, String productsname, Long biztypeCd, String categoryCd, String subcategoryCd, String extracategoryCd, String openkbn1) {
        log.debug("products:{}, productsname:{}, biztypeCd:{}, categoryCd:{}, subcategoryCd:{}, extracategoryCd:{}, openkbn1:{}", products, productsname, biztypeCd, categoryCd, subcategoryCd, extracategoryCd, openkbn1);
        Shohin shohin = new Shohin(products, productsname, biztypeCd, categoryCd, subcategoryCd, extracategoryCd, openkbn1, new Date(), new Date(),

・DBエレメントのオブジェクトをDBから取得しておく。これをしておかないと、この後の処理でShohinエンテティを読んだときこのオブジェクトはnullになっているので。

                     biztypeRepository.findByPrimaryKey(biztypeCd),
                     categoryRepository.findByPrimaryKey(categoryCd),
                     subcategoryRepository.findByPrimaryKey(categoryCd,subcategoryCd),
                     extracategoryRepository.findByPrimaryKey(categoryCd,subcategoryCd,extracategoryCd));

・商品情報を保存してフラッシュしている。

        shohinRepository.save(shohin);
        shohinRepository.flush();
    }

・@Transactional((rollbackFor=Throwable.class)で登録更新でき、Throwable発生の時ロールバックするトランザクションにする

    /**
     * registerメソッド
     * 商品情報一覧を登録する
     */
    @Transactional(rollbackFor=Throwable.class)
    @Override
    public List<Shohin> registerForShohinInsUpdListForm(List<ShohinUpload> shohinList) {
        List<Shohin> rslt = new ArrayList<Shohin>();
        //レコードの数分主キー作成(seqService.getDbSeqで、キーに必要な数だけカウントUPしている)
        String products = seqService.getDbSeq("shohin", shohinProductsLen, "あり", 6, shohinList.size());
        //先頭7文字抽出
        String productsHead = products.substring(0,7);
        //後ろの数字(3文字)抽出
        int productsCount = Integer.parseInt(products.substring(7));
        //DB登録
        for (ShohinUpload shohinUpload: shohinList) {
            products = productsHead + String.format("%03d", productsCount++);
            log.debug("products:{}, productsname:{}, biztypeCd:{}, categoryCd:{}, subcategoryCd:{}, extracategoryCd:{}, openkbn1:{}", products, shohinUpload.getProductsname(), shohinUpload.getBiztypeCd(), shohinUpload.getCategoryCd(), shohinUpload.getSubcategoryCd(), shohinUpload.getExtracategoryCd(), shohinUpload.getOpenkbn1());
            Shohin shohin1 = new Shohin(products, shohinUpload.getProductsname(), shohinUpload.getBiztypeCd(), shohinUpload.getCategoryCd(), shohinUpload.getSubcategoryCd(), shohinUpload.getExtracategoryCd(), shohinUpload.getOpenkbn1(), new Date(), new Date(),

・DBエレメントのオブジェクトをDBから取得しておく。これをしておかないと、この後の処理でShohinエンテティを読んだときこのオブジェクトはnullになっているので。

                     biztypeRepository.findByPrimaryKey(shohinUpload.getBiztypeCd()),
                     categoryRepository.findByPrimaryKey(shohinUpload.getCategoryCd()),
                     subcategoryRepository.findByPrimaryKey(shohinUpload.getCategoryCd(),shohinUpload.getSubcategoryCd()),
                     extracategoryRepository.findByPrimaryKey(shohinUpload.getCategoryCd(),shohinUpload.getSubcategoryCd(),shohinUpload.getExtracategoryCd()));

・商品情報を保存している。

            shohinRepository.save(shohin1);
            rslt.add(shohin1);
        }

・商品情報をフラッシュしている。

        shohinRepository.flush();
        return rslt;
    }

・@Transactional((rollbackFor=Throwable.class)で登録更新でき、Throwable発生の時ロールバックするトランザクションにする

    /**
     * registerメソッド
     * 商品情報をファイルアップロードで登録する
     * 補足:単項目チェック、複合項目チェックを行っている。
     */
    @Transactional(rollbackFor=Throwable.class)
    @Override

・データチェック処理に@Validを付ける。単体チェックはこれで行っています。
・実際@Validを動かすにはShohinServiceImplに@Validatedを付ける必要があります。これがないと、@Validは無視されます。結果エラー時、ConstraintViolationExceptionが発生し、エラーメッセージがセットされます。

    public void registerForShohinUpCsvDo(@Valid List<ShohinUpload> shohinList) {
        
        // 行番号、項目のエラーメッセージ
        HashMap<Integer, ArrayList<String>> hashMap = new HashMap<>();
        // 項目昇順のエラーメッセージ
        ArrayList<String> list = new ArrayList<String>();
        int i = 0;
        boolean errFlg = false;

・単体チェック以外のチェックはここで行っています。DBエレメント 、固定エレメントのチェックが自動作成されています。

       //複合チェックを行う
        for (ShohinUpload shohinUpload: shohinList) {
            boolean biztypeCdFlg = true;
            boolean categoryCdFlg = true;
            boolean subcategoryCdFlg = true;
            //『大分類』がbiztypeテーブルにあればtrue(削除されているものは取得しない)
            if (!dbElementsService.isCheckBiztypeCd(shohinUpload.getBiztypeCd(), false)) {
                biztypeCdFlg = false;
                errFlg = true;
                Functions.setErrorMsg(hashMap, Integer.valueOf(i+2), list, 
                        "biztypeCd:『業種id』を正しく入力してください");
            }
            //『大分類』がcategoryテーブルにあればtrue(削除されているものは取得しない)
            if (!dbElementsService.isCheckCategoryCd(shohinUpload.getCategoryCd(), false)) {
                categoryCdFlg = false;
                errFlg = true;
                Functions.setErrorMsg(hashMap, Integer.valueOf(i+2), list, 
                        "categoryCd:『大分類』を正しく入力してください");
            }
            //『中分類』がsubcategoryテーブルにあればtrue(削除されているものは取得しない)
            if (!dbElementsService.isCheckSubcategoryCd(shohinUpload.getCategoryCd(), shohinUpload.getSubcategoryCd(), false, categoryCdFlg)) {
                subcategoryCdFlg = false;
                errFlg = true;
                Functions.setErrorMsg(hashMap, Integer.valueOf(i+2), list, 
                        "subcategoryCd:『中分類』を正しく入力してください");
            }
            //『小分類』がextracategoryテーブルにあればtrue(削除されているものは取得しない)
            if (!dbElementsService.isCheckExtracategoryCd(shohinUpload.getCategoryCd(), shohinUpload.getSubcategoryCd(), 
                                        shohinUpload.getExtracategoryCd(), false, subcategoryCdFlg)) {
                errFlg = true;
                Functions.setErrorMsg(hashMap, Integer.valueOf(i+2), list, 
                        "extracategoryCd:『小分類』を正しく入力してください");
            }
            if (!shohinUpload.isCheckOpenkbn1()) {
                errFlg = true;
                Functions.setErrorMsg(hashMap, Integer.valueOf(i+2), list, 
                        "openkbn:『公開区分』を正しく入力してください");
            }
            i++;
        }
        //複合チェックエラー
        if (errFlg) {
            for (Map.Entry<Integer, ArrayList<String>> entry : hashMap.entrySet()) {
                // 項目昇順にする
                Collections.sort(entry.getValue());
            }
            //複合チェックエラー例外発生
            throw new UploadComplexValidException(hashMap);
        }

・レコードの数分主キーを作成(seqService.getDbSeqで、キーに必要な数だけカウントUPしている)している。
・seqService.getDbSeqは@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=Throwable.class)なので、別トランザクションで実行されている。

        //レコードの数分主キー作成(seqService.getDbSeqで、キーに必要な数だけカウントUPしている)
        String products = seqService.getDbSeq("shohin", shohinProductsLen, "あり", 6, shohinList.size());
        //先頭7文字抽出
        String productsHead = products.substring(0,7);
        //後ろの数字(3文字)抽出
        int productsCount = Integer.parseInt(products.substring(7));
        //DB登録
        for (ShohinUpload shohinUpload: shohinList) {
            products = productsHead + String.format("%03d", productsCount++);
            log.debug("products:{}, productsname:{}, biztypeCd:{}, categoryCd:{}, subcategoryCd:{}, extracategoryCd:{}, openkbn1:{}", products, shohinUpload.getProductsname(), shohinUpload.getBiztypeCd(), shohinUpload.getCategoryCd(), shohinUpload.getSubcategoryCd(), shohinUpload.getExtracategoryCd(), shohinUpload.getOpenkbn1());
            Shohin shohin1 = new Shohin(products, shohinUpload.getProductsname(), shohinUpload.getBiztypeCd(), shohinUpload.getCategoryCd(), shohinUpload.getSubcategoryCd(), shohinUpload.getExtracategoryCd(), shohinUpload.getOpenkbn1(), new Date(), new Date(),

・DBエレメントのオブジェクトをDBから取得しておく。これをしておかないと、この後の処理でShohinエンテティを読んだときこのオブジェクトはnullになっているので。

                     biztypeRepository.findByPrimaryKey(shohinUpload.getBiztypeCd()),
                     categoryRepository.findByPrimaryKey(shohinUpload.getCategoryCd()),
                     subcategoryRepository.findByPrimaryKey(shohinUpload.getCategoryCd(),shohinUpload.getSubcategoryCd()),
                     extracategoryRepository.findByPrimaryKey(shohinUpload.getCategoryCd(),shohinUpload.getSubcategoryCd(),shohinUpload.getExtracategoryCd()));

・商品情報を保存している。

            shohinRepository.save(shohin1);
        }

・商品情報をフラッシュしている。

        shohinRepository.flush();
    }

・@Transactional((rollbackFor=Throwable.class)で登録更新でき、Throwable発生の時ロールバックするトランザクションにする

    /**
     * deleteメソッド
     * 商品情報を主キーで削除する
     */
    @Transactional(rollbackFor=Throwable.class)
    @Override
    public void delete(String products) {
        log.info("delete shohin:products:{}", products);
        Shohin shohin = findByPk(products);

・商品情報が読めない場合、例外を発生させている。

        if (shohin == null) {
            log.error("shohin not found:products:{}", products);
            throw new RuntimeException("invalid pk");
        }

・商品情報を削除し、フラッシュしている。

        shohinRepository.delete(shohin);
        shohinRepository.flush();
    }

・@Transactional(readOnly=true)で読み取り専用のトランザクションにする
・商品情報を取得し、商品情報entityを戻している。

    /**
     * findByPkメソッド
     * 商品情報を取得する
     */
    @Transactional(readOnly = true)
    @Override
    public Shohin findByPk(String products) {
        Shohin shohin = shohinRepository.findByPrimaryKey(products);
        return shohin;
    }

・@Transactional(readOnly=true)で読み取り専用のトランザクションにする
・商品情報を取得し、商品情報のFormクラスを戻している。

    /**
     * findByPkForShohinFormメソッド
     * 商品情報画面情報を取得する
     */
    @Transactional(readOnly = true)
    @Override
    public ShohinForm findByPkForShohinForm(String products) {
        Shohin shohin = findByPk(products);
        ShohinForm shohinForm = null;
        if (shohin != null) {
            shohinForm = new ShohinForm(null, shohin.getProducts(), shohin.getProductsname(), shohin.getBiztypeCd(), shohin.getCategoryCd(), shohin.getSubcategoryCd(), shohin.getExtracategoryCd(), shohin.getOpenkbn1());
        } else {
            log.error("shohin not found:products:{}", products);

・商品情報が読めない場合、例外を発生させている。

            throw new RuntimeException("invalid pk");
        }
        return shohinForm;
    }

・@Transactional(readOnly=true)で読み取り専用のトランザクションにする
・XX情報のPKがDbエレメントから取得するPKの場合、XX情報Formクラスに、DbエレメントObjを設定する。但し、商品情報は、Dbエレメントから取得するPKを持っていないので、処理は空になります。

    /**
     * setDbEleObjForShohinFormメソッド
     * 商品情報情報一覧更新画面のPKがDbエレメントから取得する場合、DbエレメントObjを設定する
     */
    @Transactional(readOnly = true)
    @Override
    public void setDbEleObjForShohinForm(ShohinForm shohinForm) {
        //情報一覧更新画面のPKがDbエレメントから取得する場合、DbエレメントObjを設定する
        //情報一覧更新画面のPKがDbエレメントから取得しない場合、何もしない
    }

・@Transactional((rollbackFor=Throwable.class)で登録更新でき、Throwable発生の時ロールバックするトランザクションにする

    /**
     * updateメソッド
     * 商品情報を更新する
     */
    @Transactional(rollbackFor=Throwable.class)
    @Override
    public Shohin update(String products, String productsname, Long biztypeCd, String categoryCd, String subcategoryCd, String extracategoryCd, String openkbn1) {
        log.debug("products:{}, productsname:{}, biztypeCd:{}, categoryCd:{}, subcategoryCd:{}, extracategoryCd:{}, openkbn1:{}", products, productsname, biztypeCd, categoryCd, subcategoryCd, extracategoryCd, openkbn1);
        Shohin shohin = findByPk(products);
        Shohin shohinAftSave;
        //登録がある場合
        if (shohin != null) {
            shohin.setProductsname(productsname);
            shohin.setBiztypeCd(biztypeCd);
            shohin.setBiztypeCdObj(biztypeRepository.findByPrimaryKey(biztypeCd));
            shohin.setCategoryCd(categoryCd);
            shohin.setCategoryCdObj(categoryRepository.findByPrimaryKey(categoryCd));
            shohin.setSubcategoryCd(subcategoryCd);
            shohin.setSubcategoryCdObj(subcategoryRepository.findByPrimaryKey(categoryCd, subcategoryCd));
            shohin.setExtracategoryCd(extracategoryCd);
            shohin.setExtracategoryCdObj(extracategoryRepository.findByPrimaryKey(categoryCd, subcategoryCd, extracategoryCd));
            shohin.setOpenkbn1(openkbn1);

・商品情報を保存し、フラッシュしている。

            shohinAftSave = shohinRepository.save(shohin);
            shohinRepository.flush();
        } else {
            log.error("shohin not found:products:{}", products);

・商品情報が読めない場合、例外を発生させている。

            throw new RuntimeException("invalid pk");
        }
        return shohinAftSave;
    }    

・@Transactional((rollbackFor=Throwable.class)で登録更新でき、Throwable発生の時ロールバックするトランザクションにする

    /**
     * updateメソッド
     * 商品情報一覧を更新する
     */
    @Transactional(rollbackFor=Throwable.class)
    @Override
    public void updateForShohinInsUpdListForm(List<Shohin> shohinList){
        //DB更新
        for (Shohin shohin: shohinList) {
            log.debug("products:{}, productsname:{}, biztypeCd:{}, categoryCd:{}, subcategoryCd:{}, extracategoryCd:{}, openkbn1:{}", shohin.getProducts(), shohin.getProductsname(), shohin.getBiztypeCd(), shohin.getCategoryCd(), shohin.getSubcategoryCd(), shohin.getExtracategoryCd(), shohin.getOpenkbn1());
            Shohin shohin1 = findByPk(shohin.getProducts());
            //登録がある場合
            if (shohin1 != null) {
                shohin1.setProductsname(shohin.getProductsname());

・DBエレメントのオブジェクトをDBから取得しておく。これをしておかないと、この後の処理でShohinエンテティを読んだときこのオブジェクトは前のままになっているので。

                //DBエレメントのObjも更新しとかないと、画面一覧表示が更新されないので、対処した。
                if (!shohin1.getBiztypeCd().equals(shohin.getBiztypeCd())) {
                    shohin1.setBiztypeCd(shohin.getBiztypeCd());
                    shohin1.setBiztypeCdObj(biztypeRepository.findByPrimaryKey(shohin.getBiztypeCd()));
                }
                //DBエレメントのObjも更新しとかないと、画面一覧表示が更新されないので、対処した。
                if (!shohin1.getCategoryCd().equals(shohin.getCategoryCd())) {
                    shohin1.setCategoryCd(shohin.getCategoryCd());
                    shohin1.setCategoryCdObj(categoryRepository.findByPrimaryKey(shohin.getCategoryCd()));
                }
                //DBエレメントのObjも更新しとかないと、画面一覧表示が更新されないので、対処した。
                if (!(shohin1.getCategoryCd().equals(shohin.getCategoryCd()) && 
                        shohin1.getSubcategoryCd().equals(shohin.getSubcategoryCd()))) {
                    shohin1.setSubcategoryCd(shohin.getSubcategoryCd());
                    shohin1.setSubcategoryCdObj(subcategoryRepository.findByPrimaryKey(shohin.getCategoryCd(), shohin.getSubcategoryCd()));
                }
                //DBエレメントのObjも更新しとかないと、画面一覧表示が更新されないので、対処した。
                if (!(shohin1.getCategoryCd().equals(shohin.getCategoryCd()) && 
                        shohin1.getSubcategoryCd().equals(shohin.getSubcategoryCd()) && 
                        shohin1.getExtracategoryCd().equals(shohin.getExtracategoryCd()))) {
                    shohin1.setExtracategoryCd(shohin.getExtracategoryCd());
                    shohin1.setExtracategoryCdObj(extracategoryRepository.findByPrimaryKey(shohin.getCategoryCd(), shohin.getSubcategoryCd(), shohin.getExtracategoryCd()));
                }
                shohin1.setOpenkbn1(shohin.getOpenkbn1());

・商品情報を保存している。

                shohinRepository.save(shohin1);
            } else {
                log.error("shohin not found:products:{}", shohin.getProducts());

・商品情報が読めない場合、例外を発生させている。

                throw new RuntimeException("invalid pk");
            }
        }

・商品情報をフラッシュしている。

        shohinRepository.flush();                
    }

・テンプレートエンジンを使って、コンテンツと、テンプレートからメール本文を作成し、SimpleMailMessageに設定し、mailSenderでメールを送信している。

    /**
     * メールを送信する
     * 
     * @param to 宛先アドレス
     * @param from 差出人アドレス
     * @param subject メールの件名
     * @param text メールの本文
     */
    public void send(String to, String from, String subject, Shohin shohin) {
        // メール送信内容作成して設定する。
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setFrom(from);
        message.setSubject(subject);

        // メールテンプレートに設定するパラメータを設定します。
        Map<String, Object> variables = new HashMap<>();
        variables.put("products", shohin.getProducts());
        variables.put("productsname", shohin.getProductsname());
        variables.put("biztypeCd", shohin.getBiztypeCd());

・DBエレメント(業種、大分類、中分類、小分類)のEntityオブジェクト(BiztypeCdObj、CategoryCdObj、SubcategoryCdObj、ExtracategoryCdObj)から名称を取得する。

        variables.put("biztypeCdName", ObjectUtils.isEmpty(shohin.getBiztypeCdObj())?"":shohin.getBiztypeCdObj().getBizname());
        variables.put("categoryCd", shohin.getCategoryCd());
        variables.put("categoryCdName", ObjectUtils.isEmpty(shohin.getCategoryCdObj())?"":shohin.getCategoryCdObj().getCatname());
        variables.put("subcategoryCd", shohin.getSubcategoryCd());
        variables.put("subcategoryCdName", ObjectUtils.isEmpty(shohin.getSubcategoryCdObj())?"":shohin.getSubcategoryCdObj().getSubcatname());
        variables.put("extracategoryCd", shohin.getExtracategoryCd());
        variables.put("extracategoryCdName", ObjectUtils.isEmpty(shohin.getExtracategoryCdObj())?"":shohin.getExtracategoryCdObj().getExcatname());
        variables.put("openkbn1", shohin.getOpenkbn1());
        variables.put("openkbn1Name", shohin.getOpenkbn1Name());
        //テンプレートエンジンを実行
        Context context = new Context();
        context.setVariables(variables);
        //テンプレート(src/main/resources/templates/以下に配置する)のファイル名とパラメータ情報設定
        String text = springTemplateEngine.process("/mail/members/admin/shohinInsMail.txt", context);
        message.setTo(to);
        message.setFrom(from);
        message.setSubject(subject);
        message.setText(text);

・メール送信実行はコメントアウトしてあります。使用するにはメールサーバなどの環境を整える必要があります。

        //メール送信を実施する。とりあえずコメントアウトしてあります。
        //gmail使うときの補足:アバスト!アンチウイルスソフト使っているときは、
        //「プロテクション」タブ→「メインシールド」→
        //「メインシールド」(危険なメール添付書類をブロックします)で、ちょっとの間停止する。     
        //this.mailSender.send(message);

      }    
}