spring boot 初学者向け
spring bootの学習のために、フロントからバックエンドまでを大まかにどうコードを書いていけばいいかを知りたくまとめました。
簡単なフロントとバックとデータベースを作成しましたので記事として残します
結果イメージ
フロントで「user」「email」を入力して、「DBに保存」ボタンを押すと、DBに保存される
フロントで検索したいuserを文字列として入力して、「検索」ボタンを押すと、DBに保存されているuserと対となるemailが表示される
作成手順
フロントエンドの準備
1.任意の場所に「spring-kotlin-vite-mysql-study」フォルダを作成
2.ターミナルで作成したフォルダへ移動しコマンドで「npm create vite」を入力し、Project nameはfrontendと入力しEnterを押し、次に矢印キーでReactを選択しEnterを押し、Typscritpを選択しEnterを押下する。
3.frontというフォルダが中身も含め作成されるので、これをVSCodeなどで開く
4.「npm install」を実行
5.以下のフォルダ構成で
App.tsx,
api.ts,
getEmailByUsername.ts
の3つのファイルを以下のコードで作成する
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── api.ts
│ ├── assets
│ ├── getEmailByUsername.ts
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
├── tsconfig.json
App.tsxファイル
import { useState } from 'react'
import './App.css'
import {saveUser} from "./api.ts";
import {getEmailByUsername} from "./getEmailByUsername.ts";
function App() {
const [username, setUserName] = useState("");
const [email, setEmail] = useState("")
const [searchUsername, setSearchUsername] = useState("");
const [fetchedEmail, setFetchedEmail] = useState("")
const handleSave = async () => {
try{
const response = await saveUser({username, email});
alert(response.message)
}
catch(error){
alert("Error saving user!")
}
}
const handleSearch = async () => {
console.log("searchUsername",searchUsername)
try{
const response = await getEmailByUsername(searchUsername);
setFetchedEmail(response.email)
} catch(error){
alert("Error fetching email!")
}
}
return (
<>
<div>
<h3>DEMO</h3>
<h4>spring boot + kotlin/ vite+Typscript/ MySQL</h4>
<label>名前
<input type="text" value={username} onChange={(e) => setUserName(e.target.value)}/>
</label>
<br />
<label>メール
<input type="text" value={email} onChange={(e) => setEmail(e.target.value)}/>
</label>
<br />
<button onClick={handleSave}>DBに保存</button>
<br />
<label>検索する名前
<input type="text" value={searchUsername} onChange={(e)=>setSearchUsername(e.target.value)}/>
</label>
<br />
<button onClick={handleSearch}>検索</button>
{fetchedEmail && (
<div>
<h4>取得したメールアドレス:{fetchedEmail}</h4>
</div>
)}
</div>
</>
)
}
export default App
api.ts
export const saveUser = async (user:{username:string, email:string}) => {
const response = await fetch("http://localhost:8080/users",{
method:"POST",
headers:{"Content-Type": "application/json"},
body:JSON.stringify(user)
});
if(!response.ok) throw new Error("Failed to save user");
console.log("response",response)
return response.json()
}
getEmailByUsername.ts
export const getEmailByUsername = async (username) => {
console.log("searchUsername-getEmaulByUSername",username)
const response = await fetch(`http://localhost:8080/users/${username}`,{
method:"GET",
headers:{"Content-Type": "application/json"},
});
if(!response.ok) throw new Error("Failed to get mail");
return response.json()
}
6.「npm run dev」を実行
7.ブラウザを開き、http://localhost:5174/ を入力する
(他にnpm run devしているアプリがある時は5174ではない場合があります)
8.以下のように表示されればfrontendの準備は完了
バックエンドの準備
1.spring initializrを開く
2.Artifactに「backend」と記入し、右上のADD DEPENDENCIESを押してSring webを選択する
3.下部のGENERATEを押す
4.ダウンロードしたzipファイルを解凍して、「spring-kotlin-vite-mysql-study」の中に保存する
5.backendフォルダを開く
6.以下のフォルダ構成で
Userクラス
UserControllerクラス
UserRepositoryクラス
UserServiceクラス
application.properties
build.gradle.kts
docker-compose.yml
の7つのファイルを以下のコードで作成する
Userクラス
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
@Entity
data class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id:Long = 0,
val username:String,
val email:String
)
UserControllerクラス
package com.example.backend
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/users")
@CrossOrigin(origins = ["http://localhost:5173"])//CORS対応
class UserController (private val service:UserService){
@PostMapping
fun createUser(@RequestBody user:User):Map<String, String>{
service.saveUser(user)
return mapOf("message" to "User saved successfully!")
}
@GetMapping("/{username}")
fun getEmailByUsername(@PathVariable username: String): Map<String, String> {
val email: String? = service.findEmailByUsername(username)
return mapOf("email" to (email ?: "User not found"))
}
}
UserRepositoryクラス
package com.example.backend
import org.springframework.data.jpa.repository.JpaRepository
interface UserRepository : JpaRepository<User, Long> {
fun findByUsername(username: String): User?
}
UserServiceクラス
import org.springframework.stereotype.Service
@Service
class UserService (private val repository:UserRepository){
fun saveUser(user:User):User = repository.save(user)
fun findEmailByUsername(username:String):String?{
val user = repository.findByUsername(username)
return user?.email
}
}
application.properties
spring.application.name=mysql-test
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=user
spring.datasource.password=password6
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.cloud.config.enabled=false
#spring.config.import=configserver:
build.gradle.kts
plugins {
kotlin("jvm") version "1.9.25"
kotlin("plugin.spring") version "1.9.25"
id("org.springframework.boot") version "3.4.0"
id("io.spring.dependency-management") version "1.1.6"
kotlin("plugin.jpa") version "1.9.10"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
extra["springCloudVersion"] = "2024.0.0"
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.springframework.cloud:spring-cloud-starter-config")
runtimeOnly("com.mysql:mysql-connector-j")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation("org.mockito.kotlin:mockito-kotlin:5.1.0") // 最新版を使用
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(group = "org.mockito", module = "mockito-core")
}
implementation("jakarta.persistence:jakarta.persistence-api:3.1.0") // Jakarta Persistence API
implementation("org.springframework.boot:spring-boot-starter-data-jpa") // Spring Data JPA
}
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
}
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
docker-compose.yml
version: '3.8'
services:
mysql:
image: mysql:latest
container_name: mysql-kotlin-2024_12_09
restart: always
environment:
MYSQL_USER: user
MYSQL_ROOT_PASSWORD: mysql112233
MYSQL_PASSWORD: password6
MYSQL_DATABASE: demo
ports:
- "3306:3306"
volumes:
- ./mysql_data:/var/lib/mysql # ローカルディレクトリを指定
volumes:
mysql_data:
バックエンドの起動方法
9.dockerの起動
Macターミナルで、上記で作成したdocker-compose.ymlファイルがある場所で
docker compose up -d
を実行
10.BackendApplicaiton.ktでバックエンド起動(再生ボタン押下)
フロント→バックエンド→データベースへの動作確認
11.先ほどnpm run devで起動したフロント画面で、userとemailを入力して、「DBに保存」ボタンを押す。
12.先ほどuser欄で入力した文字を検索する名前の欄に入力して「検索」を押すと、emailが表示される
13.以上
これでフロントエンド→バックエンド→データベースの動作がspringではどうやって動作するのがかイメージするのに役立てればと思います。
参考
mysqlへ直接データが保存されているかの確認方法
・ターミナルで
docker exec -it mysql-kotlin-2024_12_09 mysql -u root -p
mysql112233
USE demo;
select * from user;
8080が起動しているか確認するコマンド
lsof -i:8080
停止は kill プロセスID