DBに登録されたステータスコードをJava側でコード値に変換するサンプルです。
これにより、ステータスコードの意味を定義するマスタを作成する必要がなくなります。
フレームワークはSpring Boot。
環境
- OS:Windows10
- IDE:Eclipse2020-03
- Java:8
- MySQL:5.7
- Hibernate ORM:5.4
- Spring Boot:2.3.1
概要
生徒テーブルに登録された生徒ステータスコード(整数値)をJava側でenumを用いて対応するコード値に変換します。
ER図
ステータスコードとコード値
ステータスコード | コード値 |
---|---|
1 | 在学中 |
2 | 休学中 |
3 | 卒業 |
パッケージ構成図
enum-sample
|
src/main/java
|----jp.co.high_school
| |---- app
| | |---- controller
| | |---- response
| |
| |---- domain
| | |---- service
| | |---- repository
| | |---- model
| |
| |---- constant
|
src/main/resources
|----application.yml
ソースコード
1. DDL
CREATE TABLE `students` (
`student_id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT COMMENT '生徒ID',
`student_name` varchar(300) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '生徒名',
`sex` tinyint(4) DEFAULT NULL COMMENT '性別',
`school_year` tinyint(4) DEFAULT NULL COMMENT '学年',
`class` tinyint(4) DEFAULT NULL COMMENT 'クラス',
`student_status` tinyint(4) DEFAULT NULL COMMENT '生徒ステータス',
PRIMARY KEY (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='生徒';
2. 定数クラス
定数クラスにenumを定義して使用します。
クラスとしてenumを作成してもよいのですが、数が多くなることを想定してクラス内に定義しました。
こうすることで1クラスファイルで複数のenumを管理することができます。
package jp.co.high_school.constant;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.Getter;
/**
* 定数クラス
* @author CHI-3
* @Version 1.0
*/
public class Constant {
/**
* StudentStatus
* 生徒ステータス
*/
@Getter
public static enum StudentStatus {
In(1, "在学中"),
Rest(2, "休学中"),
Out(3, "卒業");
private StudentStatus(int key, String value) {
this.key = key;
this.value = value;
}
private int key;
private String value;
// コード値を全て返す
public static Stream<StudentStatus> stream(){
return Stream.of(StudentStatus.values());
}
// 取得したコードに一致するコード値を返す
public static String getStatusValue(Byte code) {
return Stream.of(StudentStatus.values()).filter(v -> v.getKey() == code).map(v -> v.getValue()).collect(Collectors.joining());
}
}
// 今回は使用しない:1クラス内に複数enum定義できることの証明として記述
/**
* Grade
* 成績
*/
@Getter
public static enum Grade{
// 優、良、可は最低条件-sam、不可は最高条件
Excellent(1, "優", 90),
Good(2, "良", 75),
Passing(3, "可", 60),
Failing(4, "不可", 59);
private Grade(int key, String value, int order) {
this.key = key;
this.value = value;
this.order = order;
}
private int key;
private String value;
private int order;
}
}
3. Entityクラス
今回は、EclipseのHibernate Toolsを用いて、DBより自動生成しました。
package jp.co.high_school.domain.model;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the students database table.
*
*/
@Entity
@Table(name="students")
@NamedQuery(name="Student.findAll", query="SELECT s FROM Student s")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="student_id")
private Integer studentId;
@Column(name="class")
private Byte class_;
@Column(name="school_year")
private Byte schoolYear;
private Byte sex;
@Column(name="student_name")
private String studentName;
@Column(name="student_status")
private Byte studentStatus;
//bi-directional one-to-one association to Grade
@OneToOne(mappedBy="student")
private Grade grade;
public Student() {
}
public Integer getStudentId() {
return this.studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public Byte getClass_() {
return this.class_;
}
public void setClass_(Byte class_) {
this.class_ = class_;
}
public Byte getSchoolYear() {
return this.schoolYear;
}
public void setSchoolYear(Byte schoolYear) {
this.schoolYear = schoolYear;
}
public Byte getSex() {
return this.sex;
}
public void setSex(Byte sex) {
this.sex = sex;
}
public String getStudentName() {
return this.studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public Byte getStudentStatus() {
return this.studentStatus;
}
public void setStudentStatus(Byte studentStatus) {
this.studentStatus = studentStatus;
}
public Grade getGrade() {
return this.grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
}
4. Repositoryクラス
生徒IDの指定により、該当する生徒の情報を取得します。
package jp.co.high_school.domain.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import jp.co.test_shop.domain.model.Student;
/**
* 生徒(students)テーブル操作用リポジトリクラス
* @author CHI-3
* @Version 1.0
*/
@Repository
public interface StudentRepository extends JpaRepository<Student, Integer>{
/**
* findByStudentIdメソッド
* 生徒IDに対応する生徒を取得する
* @param studentId
* @return 生徒
*/
public Student findByStudentId(Integer studentId);
}
5. Serviceクラス
取得した生徒の、生徒ステータスのコードを対応するステータスコードに変換して返します。
package jp.co.high_school.domain.service;
import java.util.Optional;
import org.springframework.stereotype.Service;
import jp.co.test_shop.constant.Constant.StudentStatus;
import jp.co.test_shop.domain.model.Student;
import jp.co.test_shop.domain.repository.StudentRepository;
import lombok.RequiredArgsConstructor;
/**
* 生徒情報取得用サービスクラス
* @author CHI-3
* @version 1.0
*/
@Service
@RequiredArgsConstructor
public class StudentInformationService {
private final StudentRepository studentRepository;
/**
* getStatusメソッド
* 対象の生徒の生徒ステータス(コード値)を取得する
* @param studentId 生徒ID
* @return 生徒ステータス(コード値)
*/
public String getStatus(Integer studentId) throws Exception{
Student student = studentRepository.findByStudentId(studentId);
// 生徒IDに紐づく生徒が存在しない場合、例外を発生させる
Optional.ofNullable(student).orElseThrow(Exception::new);
String status = null;
/* ステータスコード → 対応するコード値:streamによる記述に変更のためコメントアウト
for(StudentStatus ss:StudentStatus.values()){
if(ss.getKey() == student.getStudentStatus()) {
status = ss.getValue();
break;
}
}
*/
// ステータスコード → 対応するコード値
status = StudentStatus.getStatusValue(student.getStudentStatus());
return status;
}
}
6. Controllerクラス
Serviceクラスで取得したコード値を整形して返します。
package jp.co.high_school.app.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import jp.co.test_shop.app.response.StudentStatusResponse;
import jp.co.test_shop.domain.service.StudentInformationService;
import lombok.RequiredArgsConstructor;
/**
* 生徒情報取得用コントローラークラス
* @author CHI-3
* @Version 1.0
*/
@RestController
@RequiredArgsConstructor
public class StudentInformationController {
private final StudentInformationService studenInformationService;
/**
* getStatusメソッド
* 生徒ステータスを取得する
* @param studentId 生徒ID
* @return レスポンスエンティティ(ステータスのコード値+HTTPステータス)
*/
@GetMapping("/student-information/{studentId}")
public ResponseEntity<StudentStatusResponse> getStatus(@PathVariable("studentId") Integer studentId){
String status = studenInformationService.getStatus(studentId);
StudentStatusResponse studentStatusReponse = StudentStatusResponse.builder().status(status).build();
return new ResponseEntity<>(studentStatusReponse, HttpStatus.OK);
}
}
7. Responseクラス
package jp.co.high_school.app.response;
import lombok.Builder;
import lombok.Getter;
/**
* 生徒ステータスレスポンスクラス
* 生徒ステータスの成形に使用
* @author CHI-3
* @Version 1.0
*/
@Getter
@Builder
public class StudentStatusResponse {
private String status;
}
動作確認
今回はローカル環境で動作確認を行います。
生徒(students)テーブル
student_id | student_name | sex | school_year | class | student_status |
---|---|---|---|---|---|
1 | 在学中 | 1 | 1 | 2 | 1 |
生徒テーブルが上記の内容の場合、API(Advanced Rest Clientを使用)を叩くと以下のような結果が返ります。
きちんと、ステータスコード(1)に対応するコード値(在学中)がとれていますね。
メソッド | GET |
---|---|
URL | http://localhost:8080/student-information/1 |
変更履歴
- 2020/07/13:ステータスコード → 対応するコード値を取得する処理の記述、定数クラスのパッケージ構成を変更
終わりに
enumを用いれば、マスタ(DB)や定数(Java)の管理がかなり楽になりそう。
うまく使っていきたいところです。