π κ°μ
μ§λλ²μ μμ±νλ λΈλ‘κ·Έμ λ΄μ©μ μμ κΈ°μ΄μ μΈ λ΄μ© λ° μ€μ μ λν΄μ μ€λͺ μ νλ€λ©΄ μ΄λ²μλ μΈλΆμ μΌλ‘ μν μ½λλ₯Ό μμ νλ©΄μ λμ¨ λ΄μ©μ λν΄μ μ 리λ₯Ό νκ³ μμ κ°μ νλ μκ°μ μ μ΄ λ³΄λ €κ³ νλ€. :)
π ꡬ쑰
BackEnd
λ΄κ° μ΄λ² νλ‘μ νΈμμ μ‘μ ꡬ쑰λ λλ©μΈ ꡬ쑰μ΄λ€. κ³μΈ΅ν ꡬ쑰μ λλ©μΈ ꡬ쑰μ λν΄μ λΉκ΅λ₯Ό νλ λΈλ‘κ·Έλ€μ λ§μ΄ 보μλ€.λ΄μ©μ μ΄ν΄λ³΄λ©΄ μκ² μ§λ§ μ λ΅μ μλ€. μ₯λ¨μ μ λ°λΌμ νλ‘μ νΈμ λ§λ ꡬ쑰λ₯Ό μ¬μ©ν΄μ κ°λ°μ μ§ννλ©΄ λλ€. (μ μ§λ³΄μλ₯Ό μν΄μλΌλ)
λ³Έλ‘ μΌλ‘ λμμμ λλ©μΈ ꡬ쑰λ₯Ό μ‘μ μ΄μ μ λν΄μ μ€λͺ νλλ‘ νκ² λ€.
- ν¨ν€μ§λ³ λΆλ¦¬λ₯Ό νμλ λ΄μ©μ νμ νλλ° λ μ½λ€κ³ νλ¨
- νλ‘μ νΈ κ°λ°κ°μ κΈ°νμ΄ λ³κ²½λλ μν©μ΄ λ§μ΄ λ°μνλλ° μ΄λ μ 리νλ€κ³ νλ¨
- νμ₯μ±μ κ³ λ €νμλ λμμ§ μμ κ±° κ°λ€λ νλ¨
κ°λ¨νκ² μ΄μ λ₯Ό μ μ΄λ΄€λ€. νμ¬ μ κ· νλ‘μ νΈμ κ·λͺ¨κ° ν¬μ§ μμμ μ¬μ€ μ΄λ€ κ΅¬μ‘°λ‘ ν΄λ μκ΄μ΄ μλ μν©μ΄λΌμ μ νμ νκ³ , μ΄ν νμ₯μ±μ κ³ λ €νμ λ λλ©μΈ κ΅¬μ‘°λ‘ ν΄λ λμμ§ μλ€κ³ νλ¨μ νλ€.
μμ μ μλ£ν μν ꡬ쑰μ΄λ€. μλ¬κ° λλ μ΄μ μ Intellij μ λ°μ΄νΈλ₯Ό νκ³ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ€μ΄ λ°κ³ λΉλλ₯Ό νμ§ μμμ μκ²Όλ€. :(
λ€λ₯Έ κ°λ°μλΆλ€μ΄ μμ νλ λλ©μΈ ꡬ쑰μ λ€λ₯΄μ§ μλ€. λλ©μΈμ κΈ°μ€μΌλ‘ λΆλ¦¬λ₯Ό ν΄μ ꡬνμ ν μμ μ΄κ³ , global ν¨ν€μ§μμλ 곡ν΅μΌλ‘ ꡬνν΄μΌ νλ λΆλΆμ λν λ΄μ©μ ꡬνν μμ μ΄λ€. (μμ μ΄λ―Έμ§ μ°Έμ‘°)
Front
vueμ κ²½μ°λ viteλ₯Ό ν΅ν΄μ νλ‘μ νΈλ₯Ό μμ±νλ€.
vite, cliλ±λ± vue νλ‘μ νΈλ₯Ό λ§λλ λ°©λ²μ λ§λ€.
npm create vite@latest
viteλ₯Ό ν΅ν΄μ νλ‘μ νΈλ₯Ό λ§λ€κ² λλ©΄ vue λΏλ§ μλλΌ λ€λ₯Έ νλ‘μ νΈλ λ§λ€ μ μλ€.
νΉμ λμ κ°μ΄ viteλ₯Ό ν΅ν΄μ νλ‘μ νΈλ₯Ό λ§λλ κ²½μ°μλ 곡μ ννμ΄μ§μ κ°μ΄λκ° μλμ΄ μμΌλ νλ² μ½μ΄λ³΄κ³ μ§ν νλ©΄ μ’λ€.
vite, cli λ± vue νλ‘μ νΈλ₯Ό μμ±νλ©΄ λμ€λ κΈ°λ³Έμ μΈ κ΅¬μ‘°μ΄λ€. μλ§ config λͺ μΉμ΄ μ’ λ€λ₯Ό κ²μ΄λ€. configμ κ²½μ°λ μ΄λ€ λꡬλ₯Ό μ¬μ©ν΄μ λ§λ€μλμ λ°λΌμ λ°©λ²μ΄ λ€λ₯΄λκΉ μ°Ύμλ³΄κ³ λ΄μ© μμ§κ° νμνλ€.
μΆκ°μ μΌλ‘ μν μ½λ μμ±μ μν λ΄μ©μ΄ μ‘°κΈ μΆκ° λμ΄ μλλ° μΈλΆ λ΄μ©μ λ°λ‘ μ€λͺ νλλ‘ νκ² λ€.
π μν μ½λ
μν μ½λλ₯Ό ꡬννλ©΄μ κ°κ° μμλλ©΄ μ’μ λ΄μ©μ λν΄μ μ 리ν λ΄μ©μ΄λ€.
BackEnd
DGSλ₯Ό μ¬μ©νλ€κ³ ν΄μ κΈ°μ‘΄μ μ¬μ© νλ Graphql μ¬μ©κ³Ό ν¬κ² λ¬λΌμ§λ λΆλΆμ μ‘΄μ¬νμ§ μλλ€. νΉμ λμ²λΌ spqrμ μ¬μ©νμ§ μμλ€λ©΄.. :) κΈ°λ³Έμ μΌλ‘ μ€ν€λ§λ₯Ό μ μ νκ³ μλΉμ€λ₯Ό ꡬνν΄μ grapgqlμμ νΈμΆν΄μ μ¬μ©νλ λ°©μ κ·Έλλ‘λ₯Ό λ°λΌκ°λ€.
DGS νλ¬κ·ΈμΈλ μμΌλ κ°μ΄ μ¬μ©νλ©΄ κ°λ°νλλ° λμμ μ£Όκ² λλ€ (μλ μ΄λ―Έμ§ μ°Έμ‘°)
μμ νλ¬κ·ΈμΈ μ¬μ© λ°©λ²κ³Ό μ΄μ΄μ§λ sample.graphqls νμΌμ μμ±ν λ΄μ©μ μ€λͺ νλλ‘ νκ² λ€.
μλμ μ΄λ―Έμ§λ μν μ€ν€λ§λ₯Ό μμ±ν λ΄μ©μ΄λ©°, μ°μΈ‘μ DGS μμ΄μ½μ λλ₯΄κ² λλ©΄ 맡νλλ μλΉμ€λ‘ μ΄μ΄μ§λλ‘ ν΄μ€λ€. μ€ν€λ§ μ μλ₯Ό μν΄λλλ€λ©΄ μ€ν€λ§λ₯Ό νμΈνκ³ νμνλ€λ©΄ ꡬνλ μλΉμ€λ‘ κ°μ λ΄μ© νμΈκΉμ§ κ°λ₯νλ€λ μ₯μ μ΄ μλ€.
μΆκ°μ μΌλ‘ μ€ν€λ§μμ μ€μΉΌλΌ νμ μ μ¬μ©νλ €λ©΄ λΌμ΄λΈλ¬λ¦¬λ₯Ό μΆκ°νκ³ μ¬μ©ν΄μΌ νλ€. μ΄μ κ²μκΈμμ build.gradleμ λΌμ΄λΈλ¬λ¦¬ λ΄μ©μ μ°Έμ‘°νκΈ° λ°λλ€.
μλμ λ΄μ©μ μ€μ μλΉμ€λ₯Ό ꡬνν μν μλΉμ€ μ½λμ΄λ€.
μ£Όμ κΉκ² λ΄μΌ νλ μ μ DGSμμ μ 곡 ν΄μ£Όλ μ΄λ Έν μ΄μ μ μ¬μ©νλ€λ κ²μ΄λ€. μΈλΆμ μΈ ν΄λμ€ λ΄μ©μ μΌλΆλ‘ λ΄μ©μ μ κ±°νλ€.
@DgsComponent
class SampleServiceImpl(
private val queryFactory: JPAQueryFactory
) : SampleService {
@DgsQuery
@Transactional(readOnly = true)
override fun findTestList(): List<test_info> {
return null;
}
@DgsQuery
@Transactional(readOnly = true)
override fun findTestInfoById(key: Long): test_info? {
return null;
}
@DgsMutation
@Transactional
override fun saveTestInfo(userInfo: add_test_info): executeQueryResult? {
return null;
}
}
sample.graphqls μ μ°κ²°λλ μμ΄μ½μ΄ λμ€κ³ ν΄λ¦νλ©΄ μ°κ²°λ μ€ν€λ§λ‘ μ΄λμ΄ λλ€.
Front
μλ¨μ κ²½μ°λ μ€ν μ΄λ₯Ό μ¬μ©νλ λ°©μμ΄ μ’ λ°λμλ€. μ무λλ vuex μμ piniaλ‘ μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ³κ²½νλ©΄μ μκΈ΄ λ΄μ©μ΄λ€.
κ°λ¨νκ² κ³΅μ λ¬Έμμ λμμλ μ€ν μ΄μ μ¬μ© λ°©λ²μ λν΄μ μ€λͺ νμλ©΄ ν¬κ² μ μ μ€ν μ΄ λ°©μκ³Ό μ΅μ μ€ν μ΄ λ°©μμ΄ μ‘΄μ¬νλ€.
import {defineStore} from 'pinia'
import {ref, computed} from 'vue';
// μ
μ
μ€ν μ΄ λ°©μ
// ref() = state
// computed() = getter
// function() = actions
export const sampleStore3 = defineStore('sample', () => {
const list = ref([]);
function addList(param){
list.value.push(param);
}
const getAllList = computed(() => list.value);
return {list, addList, getAllList};
});
import {defineStore} from 'pinia'
// μ΅μ
μ€ν μ΄ λ°©μ
export const sampleStore2 = defineStore('sample', {
state: () => ({list: []}),
actions: {
addList(param){
this.list.push(param);
}
},
getters: {
getAllList(state){
return state.list;
}
}
})
μμ λ΄μ©μ μλ¨ κ°λ°μ μν΄μ μνλ‘ λκ°μ λ°©μμ λν΄μ κ°λ¨νκ² μμ ν λ΄μ©μ΄λ€. μλ§ μΈλΆμ μΌλ‘ κ°λ°μ μ§ννλ©΄ λ 볡μ‘ν΄μ§ μλ μκ³ λͺ¨λ₯΄λ λΆλΆμ΄ λμ¬ μλ μμ§λ§ κΈ°λ³Έμ μΈ λ°©μλ§ λκ³ λ³΄λ©΄ κΈ°μ‘΄ vuexμμ μ¬μ©νλ λ°©μλ³΄λ€ νΈνλ€κ³ μκ°νλ€.
λ°©μμ€μμ μ’ λ νΈν λ°©μμ μ무거λ μ¬μ©ν΄λ μκ΄μλ€κ³ νλ€. νμ§λ§ μ λͺ¨λ₯΄κ² λ€λ©΄ μ΅μ μ€ν μ΄ λ°©μμ μΆμ²νλ€κ³ 곡μ ννμ΄μ§μμλ λ§νκ³ μλ€.
API νΈμΆ
μ€ν μ΄μμ APIλ₯Ό νΈμΆν λ μ¬μ©νλ λΆλΆμ κ²½μ°λ basicInfo.js νμΌμ κ°λ°μ μ§ννκ³ μ μ€ν μ΄μμ 곡ν΅μΌλ‘ νΈμΆν΄μ μ¬μ©νλ €κ³ μμ μ νλ€. (ν μ€νΈ μλ£)
import axios from 'axios';
import {defineStore} from 'pinia'
export const basicStore = defineStore('basicStore', {
state: () => ({}),
getters: {
// getter setting
},
actions: {
async graphqlRequest(param) {
try {
const address = import.meta.env.VITE_ADDRESS
const port = import.meta.env.VITE_PORT
const result = await axios({
method: "POST",
url: `http://${address}:${port}/graphql`,
data: {
query: param
}
});
if (result.status === 203){
alert("203")
} else if (result.status === 204){
alert("204")
} else {
// μΆκ° μ€μ .
console.log(result.data.data)
}
return result.data.data;
} catch (error) {
console.error(error)
}
}
},
})
μ΄μΈ vue3μμλ computed μ methodμμ mapStateμ mapActionμ μ¬μ©νλ λ°©λ²μ΄ μ’ λ¬λΌμ‘μΌλ νμΈμ ν΄λ³΄λ κ² μ’λ€.
// μμ
export default {
data: () => ({
text: "",
}),
computed: {
...mapState(sampleStore, ["getAllList"]),
},
methods: {
...mapActions(sampleStore, ["addList"]),
onClickAddList(){
if (!this.text) return;
this.addList(this.text);
this.text = "";
},
},
};
β‘ μκ°
μ κ· νλ‘μ νΈλ₯Ό μ§ν νλ©΄μ κΈ°λ³Ένμ μμ ν λ΄μ©μ μ λ¦¬ν΄ λ³΄μλ€. μμ§ μ λλ‘ μμν κ²μ μλκΈ° λλ¬Έμ 곡ν΅μΌλ‘ νμν λ΄μ©μ μ 리νκ³ κ΅¬ννκ³ μμΌλ©°, κΈ°νμ΄ λλλλ‘ κ°λ°μ μ§νν μμ μ΄λ€.
μΆκ°μ μΌλ‘ μ κ· νλ‘μ νΈλ₯Ό νλ©΄μ λλμ μ΄μ§λ§ μλ‘ νλκΉ μ¬λ°λ€. :)
'Spring' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[JPA] Entity Default κ° μ μ₯ μ΄μ μ 리 (0) | 2024.08.21 |
---|---|
[QueryDSL] SQLQueryFactory μ¬μ©μ LocalDate νμ λ°νμ λ μ§ μλ¬ (0) | 2024.06.01 |
Spring boot + vue νλ‘μ νΈ (1) (0) | 2024.04.04 |
[JPA] Spring boot 3.x.x μμ QueryDsl Date Type μ¬μ© λ°©λ² (0) | 2024.01.09 |
[Spring] Spring boot 3.x.x λ²μ λ§μ΄κ·Έλ μ΄μ λ΄μ© μ 리 (0) | 2023.12.31 |