[java] enum 에 대해 알아보기(2)

🦥 Enum 활용

스프링MVC에서의 enum 활용

  • 스프링 mvc 에서 요청 파라미터를 String이 아닌 enum 을 활용
  • enum 을 활용하여 요청값에 타입 안정성을 부여
  • 간단한 스프링부트 어플리케이션을 통해 샘플코드를 작성함.
  • 본 블로그는 타 유명개발자의 블로그를 참조하였으며, 하단에 참조블로그 표시

  • pom.xml
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>nz.net.ultraq.thymeleaf</groupId>
            <artifactId>thymeleaf-layout-dialect</artifactId>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.github.gavlyukovskiy</groupId>
            <artifactId>p6spy-spring-boot-starter</artifactId>
            <version>1.5.6</version>
        </dependency>
 </dependencies>		
  • 간단한 직원(Employee) 관리 어플리케이션이다. 먼저 데이터 도메인을 정의한다.
@Data
public class Employee {
	
	private long id;
	private String name;
	private DutyStep dutyStep;
	
	public Employee(String name, DutyStep dutyStep) {
		this.name = name;
		this.dutyStep = dutyStep;
	}
	
	//EnumModel을 통해 클라이언트에서 enum을 key/value 형태로 사용할 수 있게 한다.
	public enum DutyStep implements EnumModel{
		
		EL("사원"), IL("대리"), VL("과장");
		
		private String dutyName;
		
		DutyStep(String dutyName){
			this.dutyName = dutyName;
		}
		
		public String getDutyName() {
			return dutyName;
		}
		
		@Override public String toString() {
			return super.toString() +"[["+ getDutyName()+"]]";
		}
		
		@Override
		public String getKey() {
			return name();
		}
		
		@Override
		public String getValue() {
			return dutyName;
		}
	}
}
  • Employee 를 저장하는 repository 를 만든다. 간단하게 메모리(Map)에 저장하는 방식으로 한다.
@Repository
public class EmployeeRepository {
	
	private static final Map<Long, Employee> map = new HashMap<>();
	private static long sequence = 0L;
	
	public Employee save(Employee emp) {
		emp.setId(++sequence);
		map.put(emp.getId(), emp);
		return emp;
	}
	
	public List<Employee> findAll(){
		return new ArrayList<>(map.values());
	}
}
  • 클라이언트에서 Select box 는 key 와 value 로 이루어져 있다.
  • 서버에서 enum 의 key 와 value 를 제공해야 하며, 해당 기능을 먼저 인터페이스로 선언한다.
public interface EnumModel {
	
	String getKey();
	String getValue();

}

  • 클라이언트에 넘길 enum Data 객체를 정의한다.
public class EnumValue {
	
	private String key;
	private String value;
	
	public EnumValue(EnumModel model) {
		this.key = model.getKey();
		this.value = model.getValue();
	}
	public String getKey() {
		return key;
	}
	public String getValue() {
		return value;
	}
}
  • 보통 공통코드는 어플리케이션 기동 초기에 로딩한다. 매번 컨트롤러에서 enum Data 를 생성하지 않기 위해 enum 제공빈을 생성한다.
public class EnumMapper {
	
	// key : enum type , value : enum 상수별 인스턴스(EnumValue)
	private Map<Class<? extends EnumModel>, List<EnumValue>> map = new HashMap<>();
	
	private List<EnumValue> toEnumValue(Class<? extends EnumModel> clazz){
		return Arrays.stream(clazz.getEnumConstants())
				.map(EnumValue::new)
				.collect(Collectors.toList());
	}
	
	public void put(Class<? extends EnumModel> clazz) {
		map.put(clazz, toEnumValue(clazz));
	}
	
	public Map<Class<? extends EnumModel>, List<EnumValue>> getAll(){
		return map;
	}
	
	public List<EnumValue> get(Class<? extends EnumModel> clazz){
		return map.get(clazz);
	}
}
  • @Configuration을 통해 EnumMapper를 빈으로 등록한다.
@Configuration
public class AppConfig {
	
	@Bean
	public EnumMapper enumMapper() {
		EnumMapper enumMapper = new EnumMapper();
		//공통 코드 enum 을 추가하려면 아래 enumMapper 에 put 을 한다. 
		enumMapper.put(Employee.DutyStep.class);
		return enumMapper;
	}
}
  • 컨트롤러를 만든다.
@Slf4j
@Controller
@RequestMapping("/employee")
@RequiredArgsConstructor
public class EmployeeController {
	
	private final EmployeeRepository repository;
	private final EnumMapper enumMapper;
	
	@GetMapping("/all")
	@ResponseBody
	public List<Employee> getEmployeeList() {
		return repository.findAll();
	}
	
	@GetMapping("/registerForm")
	public String getDutyStep(Model model){
		//select box 에서 key  와 value 로 매핑한다. 
		model.addAttribute("dutyStep", enumMapper.get(Employee.DutyStep.class));
		
		return "registerForm";
	}
	
	@PostMapping("/register")
	public String post(@RequestParam(value="dutyStepName") DutyStep type, @RequestParam(value="name") String name) {
		log.info("type is {}, {}", type, name);
		repository.save(new Employee(name, type));
		return "redirect:/employee/all";
	}
}
  • 클라이언트 html 코드를 만든다. 뷰 템플릿엔진은 Thymeleaf 를 사용한다.
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
	<div class="container">
		<form role="form" action="/employee/register" method="post">
			<div class="form-group">
				<label for="count">이름</label> <input type="text" name="name"
					class="form-control" id="name" placeholder="이름을 입력하세요">
			</div>
			<div class="form-group">
				<label for="employee">직급</label> <select name="dutyStepName"
					id="dutyStepId" class="form-control">
					<option value="">직급</option>
					<option th:each="step : ${dutyStep}" th:value="${step.key}"
						th:text="${step.value}" />
				</select>
			</div>
			<button type="submit" class="btn btn-primary">Submit</button>
		</form>
		<br />
	</div>
</body>
</html>

  • 스프링 부트 기동 클래스를 만든다.
  • 초기화 클래스에는 Employee 객체를 몇개 생성하여둔다.
@SpringBootApplication
@ComponentScan(basePackageClasses = {Page2BasePackage.class})
public class App {
	
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
	
	@Component
	@RequiredArgsConstructor
	class AppInit implements ApplicationRunner{
		
		private final EmployeeRepository repository;

		@Override
		public void run(ApplicationArguments args) throws Exception {
			repository.save(new Employee("김윤아", Employee.DutyStep.EL));
			repository.save(new Employee("김개똥", Employee.DutyStep.IL));
			repository.save(new Employee("홍길동", Employee.DutyStep.VL));
		}
	}
}

Reference

  • [블로그 참고](https://jojoldu.tistory.com/122?category=635881

Categories:

Updated:

Leave a comment