サンプルコード
AnimalController.java
package com.example.demo.controller.animal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.demo.entity.AnimalKindsEntity;
import com.example.demo.form.AnimalForm;
import com.example.demo.service.animal.AnimalService;
import lombok.RequiredArgsConstructor;
/** switch文を使用した分岐コントローラー */
@Controller
@RequiredArgsConstructor
@RequestMapping("/animal")
public final class AnimalController
{
private final AnimalService animalService;
// ==== ModelAttribute ====
@ModelAttribute("animals")
public Map<String, String> animals()
{
final List<AnimalKindsEntity> animal_kinds = animalService.getAllAnimalKindsData();
final Map<String, String> animals = new TreeMap<String, String>();
for (final AnimalKindsEntity animal_kind : animal_kinds)
{
animals.put(animal_kind.getId().toString(), animal_kind.getName());
}
return animals;
}
@ModelAttribute("form")
public AnimalForm form()
{
return new AnimalForm("", null, Collections.emptyList());
}
@ModelAttribute("display")
public String display()
{
return "display";
}
@ModelAttribute("clear")
public String clear()
{
return "clear";
}
@ModelAttribute("action")
public String action()
{
return "/animal/submit";
}
// ==========================
/** 初期表示 */
@GetMapping("/index")
public String index(final Model model)
{
model.addAttribute("test", "初期表示");
return "animal";
}
@PostMapping("/submit")
public String execute(
@RequestParam final String action,
@ModelAttribute("form") final AnimalForm animalForm,
final BindingResult error,
final Model model
)
{
model.addAttribute("form", animalForm);
// 押されたボタンにより、処理を分岐
switch (action)
{
case "display": // 表示ボタン
animalService.display(model);
break;
case "clear": // 画面クリアボタン
animalService.clear(model);
break;
default: // 初期表示ボタン
return "redirect:/animal/index";
}
return "animal";
}
}
AnimalService.java
package com.example.demo.service.animal;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import com.example.demo.entity.AnimalKindsEntity;
import com.example.demo.entity.AnimalNameEntity;
import com.example.demo.form.AnimalForm;
import com.example.demo.repository.AnimalKindsRepository;
import com.example.demo.repository.AnimalNameRepository;
import lombok.RequiredArgsConstructor;
/** switch文を使用した分岐のサービスクラス */
@Service
@RequiredArgsConstructor
public final class AnimalService
{
@Autowired
private Validator springValidator;
private final AnimalKindsRepository animalKindsRepository;
private final AnimalNameRepository animalNameRepository;
/** 表示ボタン押下時の処理 */
public void display(final Model model)
{
final AnimalForm form = (AnimalForm) model.getAttribute("form");
switch (form.getAnimalAsInt())
{
case 1:
model.addAttribute("test", "ねこ表示");
break;
case 2:
model.addAttribute("test", "いぬ表示");
break;
case 3:
model.addAttribute("test", "さる表示");
break;
}
final BindingResult bindingResult = new BeanPropertyBindingResult(form, "form");
if (!validation(model, form, bindingResult))
{
return;
}
final Optional<AnimalKindsEntity> kinds_data = getSelectedKindsData(model, bindingResult, form);
if (kinds_data.isEmpty())
{
return;
}
final List<AnimalNameEntity> name_data = animalNameRepository.findByPrimaryKeysKindsId(form.getAnimalAsInt());
form.setKinds_data(kinds_data.get());
form.setName_data(name_data);
model.addAttribute("form", form);
}
private Optional<AnimalKindsEntity> getSelectedKindsData(
final Model model, final BindingResult bindingResult, final AnimalForm form
)
{
final Optional<AnimalKindsEntity> kinds_data = animalKindsRepository.findById(form.getAnimalAsInt());
if (!kinds_data.isPresent())
{
bindingResult.rejectValue("animal", "form.animal.notexist");
model.addAttribute("org.springframework.validation.BindingResult.form", bindingResult);
return Optional.empty();
}
return kinds_data;
}
private boolean validation(final Model model, final AnimalForm form, final BindingResult bindingResult)
{
springValidator.validate(form, bindingResult);
if (bindingResult.hasErrors())
{
model.addAttribute("org.springframework.validation.BindingResult.form", bindingResult);
return false;
}
return true;
}
/** 画面クリアボタン押下時の処理 */
public void clear(final Model model)
{
final AnimalForm form = (AnimalForm) model.getAttribute("form");
switch (form.getAnimalAsInt())
{
case 1:
model.addAttribute("test", "ねこ画面クリア");
break;
case 2:
model.addAttribute("test", "いぬ画面クリア");
break;
case 3:
model.addAttribute("test", "さる画面クリア");
break;
}
form.setKinds_data(null);
form.setName_data(Collections.emptyList());
}
/**
* 画面表示ModelAttribute用
*
* @return {@code List<AnimalKindsEntity>} animal_kindsテーブルの全データ
*/
public List<AnimalKindsEntity> getAllAnimalKindsData()
{
return animalKindsRepository.findAll();
}
}
詳細説明
画面から、何かボタンが押された際、
Controllerにて設定された(52~62行目)値がactionというキーで飛んできます。
それを92行目のswitch文で分岐し、Serviceクラスの処理を実行しています。
switch文使用のメリット
switch文使用のデメリット
デメリットの修正に強くないとはどういうことか。
サンプルコードには、AnimalServiceクラスの37~48行目や102~113行目に同様の条件のswitch文があります。
もし、仕様変更やデータ追加で、例えば「とり」が追加されたとします。
そうすると、この2つのswitch文を修正する必要が出てきます。
今回のサンプルでは、2つしかないので、修正漏れは出にくいかと思いますが、
このような同様の条件のswitch文が複数個所出てくる場合があります。
そうすると、修正漏れが出やすくなり、バグの原因となります。
swtich文なので、コンパイルエラーなども出ず、バグに気が付かずにリリースされたら大変なことになるでしょう。
一概にswitch文が悪いとは言いませんが、使用するのであれば、複数個所で使用される可能性が低い場合に使用するか、修正の際に細心の注意を払ってすることが必要でしょう。
このデメリットを解消してくれるのがinterfaceの使用です。
ぜひサンプルコードをご覧ください。
参考書