#プロローグ
Java(spring boot)を触り始めてコードを書き始めて2週間程度ですが、
色々と使い方を覚えてきたので、メモとして記録を残します。
不備不足だったり、理解が浅くて説明不足なところがあるかと思いますが、
勉強して更新していきたいとは思っています。
このプログラミングを書く前の理解度としては、アノテーションも分からずでした。
spring bootも分からなかったので、Ruby on Railsと同じようにMVCでデータを取得、加工、表示するのかなと思っていました。
計算処理を行う「service」というものの存在も知りませんでした。
##この記事で何ができるようになるか
まだ自分自身もそれぞれのクラスの役割を理解してませんが、
データを受け取って表示させることができると思います。
まずは、わからないなりに手を動かして画面に表示させることで、なんとなくの流れをつかむことが大切なのかなと思います。
この記事でやることとしては、ファイル内に作成したCSVファイルを読み取って、画面上に表示させるというイメージです。
また、ただ読み取って表示させるだけではなく、合計点を算出していきたいと思います。
##Javaの構造把握
まずは、ファイルの構造を紹介していきます。
src/main/java
├ resources
├ └ files
├ └ scores.csv
├ └ templates
├ └ score.html
├ └ score
├ └ total.html
├ repository
├ └ ScoreCsvRepository.java
├ entity
├ └ ScoreEntity.java
├ serivice
├ └ ScoreService.java
├ dto
├ └ ScoreDto.java
└ controller
└ ScoreController.java
###1.CSV
resources/files/scores.csv
にあるデータをHTMLまでもっていき画面上に出したいとします。
CSVに下記のようなデータがあるとします。
name,english,math,
山田,50,38
田中,30,47
高橋,64,58
鈴木,NA,94
石井,74,28
坂本,73,85
これをイメージとしては下記画像のようにデータを渡していきます。
この記事では、「加工したデータ」というのはenglishとmathの合計点を算出したもの、とします。
フレームワークによってmodelの定義が異なるみたいです。
勉強になります・・。
【参考文献】
Webアプリケーション開発者から見た、MVCとMVP、そしてMVVMの違い
###2.Repository
Repositoryでは、CSVのデータをとってきます。
CSVデータだけではなく、DBからデータをとってくることもできます。
とってきたデータをEntityという入れ物に入れますが、
その時にどこのどのデータを入れるか、をここで書いていきます。
package repository;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import pg.skilltest.entity.ScoreEntity;
public class ScoreCsvRepository {
public List<ScoreEntity> getAllScores() {
var result = new ArrayList<ScoreEntity>();
//resultは、ArrayListで作成したデータと定義しています。
BufferedReader br = null;
String score_csv = "src/main/resources/files/scores.csv";
// 読み込みたいCSVファイルを指定します。
try {
File file = new File(score_csv);
br = new BufferedReader(new FileReader(file));
String line;
String[] data;
br.readLine();
//CSVデータの1行目は見るとわかるのですが、「name,english,math」となっています。
//この先のコードでenglishとmathの合計点を出したいので、タイトルの1行目を飛ばすために、
//「br.readLine();」とここで書くと1行目は計算されず読み込まれます。
while ((line = br.readLine()) != null) {
data = line.split(",");
var scoreEntity = new ScoreEntity();
//ここの「setGroup」などは、例えば「setGroup」の場合
//(data[0])を次のEntityに入れる棚のgroupという名前に入れるというのを示しています(わかりにくい…)
scoreEntity.setName(data[0]);
if(data[1].equals("NA") == false) {
scoreEntity.setEnglish(Integer.parseInt(data[1]));
scoreEntity.setMath(Integer.parseInt(data[2]));
} else {
scoreEntity.setEnglish(0);
scoreEntity.setMath(0);
}
result.add(scoreEntity);
}
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
try {
br.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
return result;
}
}
CSVの読み込みは、下記の記事を参考に書きました。
ありがとうございます。
【参考文献】
JavaでのCSVファイル読み込み方法とは?
###3.Entity
Repositoryで記載した「getName」などはここと連動しています。
つまり、.getName(data[0])
と書いたら、data[0]
が下記のname
に入っていくイメージです。
@Data
に関しては、便利だ!と思って使っていますが、よくわかっていないので、
@Data
なしでも書けるように便利なものも調べておきます・・。
(getName
とやってEntityにデータが入っていくのも@Data
のおかげです)
package entity;
import lombok.Data;
@Data
public class ScoreEntity {
private String name;
private Integer english;
private Integer math;
}
###4.Servic
Serviceでは、Entityにいれたデータをもってきて、加工します。
package service;
import java.util.ArrayList;
import java.util.List;
import dto.ScoreDto;
import repository.ScoreCsvRepository;
public class ScoreService {
public List<ScoreDto> getAllTotalScores() {
var result = new ArrayList<ScoreDto>();
var scoreCsvRepository = new ScoreCsvRepository();
var allScore = scoreCsvRepository.getAllScores();
for (int i = 0; i < allScore.size(); i++) {
var score = allScore.get(i);
var total = score.getEnglish() + score.getMath();
var name = score.getName();
var scoreDto = new ScoreDto();
//Entityの時と同じように、Dtoにそれぞれの値をいれています。
scoreDto.setTotal(total);
scoreDto.setName(name);
result.add(scoreDto);
}
return result;
}
}
###5.Dto
Integer など最初を大文字にすると、その値がnullの場合も入ります。
ここあたりも知らないことあるので、深堀したいです…。
package dto;
import lombok.*;
@Data
public class ScoreDto {
private String name;
private Integer total;
}
###6.Controller
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import service.ScoreService;
@Controller
public class ScoreController {
// 得点一覧画面
@RequestMapping("/score")
public String index() {
return "score";
}
// 合計画面
@RequestMapping("/score/total")
public String total(Model model) {
var scoreService = new ScoreService();
model.addAttribute("result", scoreService.getAllTotalScores());
// `.getAllTotalScores()`がServiceで記載してあるのと一致しています。
//その値を`result`に入れています。そしてHTMLに渡しています。
return "score/total";
}
}
###7.HTML
かなりざっくりですが、下記のように記載すれば、controllerからデータを受け取ることができます。
この書き方はThymeleafと呼ばれるものです。
あまり書いたことないので、(これがはじめて)ここも勉強していかないとです…。
【結果】
<p th:each="totalDto : ${result}">
<!--Controllerの`result`をここで呼び出してeachで回しています。-->
<span th:text="${totalDto.name}"></span>
<!-- Dtoで定義した`name`を呼び出しています。-->
<span th:text="${totalDto.total}"></span>
</p>
####終わりに
なんとなくJSと似ているところがあったりして、初めてプログラミングを学んだ時より理解はありましたが、
MVCだけではないクラスを使ってデータを加工するというのが初めてだったので、戸惑いがありました。
ただ、かなり整理されて作ることができるので、わかりやすいなと思いました。
まだまだなところや間違っていることがあるかと思いますので、勉強して更新していきたいです。