Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spring 지하철 경로 조회 - 1,2단계] 다니(이다은) 미션 제출합니다. #57

Merged
merged 25 commits into from
May 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6953798
docs(readme): 1단계 요구사항 정리
da-nyee May 12, 2021
7d143ac
feat(token): JWT 라이브러리를 활용하여 액세스 토큰 발급 기능을 구현
perenok May 12, 2021
74df97f
fix(dto): @NotNull import 버그 해결
da-nyee May 12, 2021
7c2d56e
feat: cors and api url
gracefulBrown May 12, 2021
a593ab9
Merge branch 'master' of https://github.com/woowacourse/atdd-subway-p…
da-nyee May 12, 2021
9be3160
feat(join): 회원가입 API 구현
da-nyee May 12, 2021
aa493a4
feat(login): 로그인 API 구현
da-nyee May 12, 2021
d710b9a
docs(readme): 2단계 요구사항 정리
da-nyee May 12, 2021
c649ce4
feat(update): 수정 API 구현
perenok May 12, 2021
36ad55d
feat(delete): 삭제 API 구현
da-nyee May 12, 2021
e26fc3e
refactor(subway): 불필요한 import 삭제
da-nyee May 12, 2021
91a84e1
refactor(login): Resolver, Interceptor 활용
da-nyee May 13, 2021
5c363a4
refactor(edit): Resolver, Interceptor 활용
da-nyee May 13, 2021
10040b1
refactor(delete): Resolver, Interceptor 활용
da-nyee May 13, 2021
b98b506
refactor(subway): 불필요한 import 삭제
da-nyee May 13, 2021
21b3333
fix(exception): Auth 인수 테스트 버그 해결
da-nyee May 13, 2021
15b2b5b
style(login): 불필요한 출력문 삭제
da-nyee May 14, 2021
7ba5d42
fix(interceptor): 경로 버그 해결
da-nyee May 14, 2021
0662f5d
refactor(interceptor): HandlerInterceptorAdapter -> HandlerIntercepto…
da-nyee May 14, 2021
b682879
refactor(resolver): token 지역변수 삭제
da-nyee May 14, 2021
13e5355
refactor(dao): 불필요한 메소드 삭제
da-nyee May 14, 2021
e54c222
refactor(service): @Transactional 추가
da-nyee May 14, 2021
332537e
style(sql): 코드 리포맷팅 제거
da-nyee May 17, 2021
a21177b
docs(readme): 2단계 요구사항 수정
da-nyee May 17, 2021
0717a4f
refactor(service): @Transactional 수정
da-nyee May 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ npm run serve
```
<br>

## 요구사항

> 1단계

- [x] JWT 라이브러리를 활용하여 액세스 토큰 발급 기능을 구현하기
- [x] 프론트엔드 코드 중 API를 호출하는 부분을 구현하여 기능이 잘 동작하도록 완성하기
<br>

> 2단계

- [x] 발급한 토큰을 이용하여 로그인이 필요한 기능(회원 정보 수정/삭제) 요청 시 포함하여 보내기
- [x] 이를 이용하여 기능이 동작하도록 리팩터링 하기
- [x] 프론트엔드 코드 중 API를 호출하는 부분을 구현하여 기능이 잘 동작하도록 완성하기

<br>

## ✏️ Code Review Process
[텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview)

Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
// spring
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-validation'

// handlebars
implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.3.0'
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"serve": "vue-cli-service serve --port 8081",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
Expand Down
17 changes: 14 additions & 3 deletions frontend/src/pages/member/JoinPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,20 @@ export default {
return;
}
try {
// TODO member를 생성하는 API를 추가해주세요.
// const { email, age, password } = this.member;
// await fetch("/join", { email, age, password })
// member를 생성하는 API를 추가해주세요.
const { email, age, password } = this.member;
let data = {
email: email,
age: age,
password: password
}
await fetch("/api/members", {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
});
this.showSnackbar(SNACKBAR_MESSAGES.COMMON.SUCCESS);
await this.$router.replace(`/login`);
} catch (e) {
Expand Down
38 changes: 32 additions & 6 deletions frontend/src/pages/member/LoginPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,38 @@ export default {
return;
}
try {
// TODO login API를 작성해주세요.
// const { email, password } = this.member;
// const data = await fetch("/login")
// TODO member 데이터를 불러와 주세요.
// const member = wait fetch("/members/me")
// this.setMember(member);
// login API를 작성해주세요.
const { email, password } = this.member;
let tokenResponse = await fetch("/api/login/token", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password
})
});
if (!tokenResponse.ok) {
throw new Error(`${tokenResponse.status}`);
}
let token = await tokenResponse.json();
localStorage.setItem("token", token.accessToken);

// member 데이터를 불러와 주세요.
let memberResponse = await fetch("/api/members/me", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token.accessToken
}
});
if (!memberResponse.ok) {
throw new Error(`${memberResponse.status}`);
}
let member = await memberResponse.json();
this.setMember(member);

await this.$router.replace(`/`);
this.showSnackbar(SNACKBAR_MESSAGES.LOGIN.SUCCESS);
} catch (e) {
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/pages/member/MyPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,16 @@ export default {
return;
}
try {
// TODO 유저를 삭제하는 API를 추가해주세요
// await fetch("/api/users/{this.member.id}")
// 유저를 삭제하는 API를 추가해주세요
await fetch("/api/members/me", {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("token")
}
});
this.setMember(null);

this.showSnackbar(SNACKBAR_MESSAGES.MEMBER.DELETE.SUCCESS);
await this.$router.replace("/");
} catch (e) {
Expand Down
97 changes: 55 additions & 42 deletions frontend/src/pages/member/MyPageEdit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,48 @@
<v-card-text class="px-4 pt-4 pb-0">
<div class="d-flex">
<v-text-field
color="grey darken-1"
label="이메일을 입력해주세요."
v-model="editingMember.email"
prepend-inner-icon="mdi-email"
dense
outlined
:rules="rules.member.email"
color="grey darken-1"
label="이메일을 입력해주세요."
v-model="editingMember.email"
prepend-inner-icon="mdi-email"
dense
outlined
:rules="rules.member.email"
></v-text-field>
</div>
<div class="d-flex mt-2">
<v-text-field
color="grey darken-1"
label="나이를 입력해주세요."
v-model="editingMember.age"
prepend-inner-icon="mdi-account"
dense
outlined
:rules="rules.member.age"
color="grey darken-1"
label="나이를 입력해주세요."
v-model="editingMember.age"
prepend-inner-icon="mdi-account"
dense
outlined
:rules="rules.member.age"
></v-text-field>
</div>
<div class="d-flex mt-2">
<v-text-field
color="grey darken-1"
label="비밀번호를 입력해주세요."
v-model="editingMember.password"
prepend-inner-icon="mdi-lock"
type="password"
dense
outlined
:rules="rules.member.password"
color="grey darken-1"
label="비밀번호를 입력해주세요."
v-model="editingMember.password"
prepend-inner-icon="mdi-lock"
type="password"
dense
outlined
:rules="rules.member.password"
></v-text-field>
</div>
<div class="d-flex mt-2">
<v-text-field
color="grey darken-1"
label="비밀번호를 한번 더 입력해주세요."
type="password"
prepend-inner-icon="mdi-lock"
dense
outlined
v-model="editingMember.confirmPassword"
:rules="[
color="grey darken-1"
label="비밀번호를 한번 더 입력해주세요."
type="password"
prepend-inner-icon="mdi-lock"
dense
outlined
v-model="editingMember.confirmPassword"
:rules="[
(editingMember.password &&
editingMember.password === editingMember.confirmPassword) ||
'비밀번호가 일치하지 않습니다.',
Expand All @@ -64,10 +64,10 @@
취소
</v-btn>
<v-btn
@click.prevent="onEditMember"
:disabled="!valid"
color="amber"
depressed
@click.prevent="onEditMember"
:disabled="!valid"
color="amber"
depressed
>
확인
</v-btn>
Expand All @@ -79,9 +79,9 @@
</template>

<script>
import { mapGetters, mapMutations } from "vuex";
import { SET_MEMBER, SHOW_SNACKBAR } from "../../store/shared/mutationTypes";
import { SNACKBAR_MESSAGES } from "../../utils/constants";
import {mapGetters, mapMutations} from "vuex";
import {SET_MEMBER, SHOW_SNACKBAR} from "../../store/shared/mutationTypes";
import {SNACKBAR_MESSAGES} from "../../utils/constants";
import validator from "../../utils/validator";

export default {
Expand All @@ -90,7 +90,7 @@ export default {
...mapGetters(["member"]),
},
created() {
const { email, age } = this.member;
const {email, age} = this.member;
this.editingMember = {
email,
age,
Expand All @@ -105,9 +105,22 @@ export default {
},
async onEditMember() {
try {
// TODO member 정보를 update하는 API를 추가해주세요
// const { email, age, password } = this.editingMember;
// await fetch("/api/users/{this.member.id}", { email, age, password })
// member 정보를 update하는 API를 추가해주세요
const {email, age, password} = this.editingMember;
await fetch("/api/members/me", {
method: 'PUT',
body: JSON.stringify({
email: email,
age: age,
password: password
}),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("token")
}
});
this.setMember(this.editingMember);

this.showSnackbar(SNACKBAR_MESSAGES.MEMBER.EDIT.SUCCESS);
await this.$router.replace("/mypage");
} catch (e) {
Expand All @@ -120,7 +133,7 @@ export default {
return {
editingMember: {},
valid: false,
rules: { ...validator },
rules: {...validator},
};
},
};
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/station/StationPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default {
},
async created() {
// TODO 초기 역 데이터를 불러오는 API를 추가해주세요.
const response = await fetch("/api/stations");
const response = await fetch("http://localhost:8080/stations");
if (!response.ok) {
throw new Error(`${response.status}`);
}
Expand All @@ -84,7 +84,7 @@ export default {
}
try {
// TODO 역을 추가하는 API Sample
const response = await fetch("/api/stations", {
const response = await fetch("http://localhost:8080/stations", {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand Down Expand Up @@ -113,7 +113,7 @@ export default {
async onDeleteStation(stationId) {
try {
// TODO 역을 삭제하는 API를 추가해주세요.
// await fetch("/api/stations/{id}");
// await fetch("http://localhost:8080/stations/{id}");
const idx = this.stations.findIndex(
(station) => station.id === stationId
);
Expand Down
16 changes: 12 additions & 4 deletions frontend/vue.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
const path = require('path');
module.exports = {
transpileDependencies: [
'vuetify'
]
}
outputDir: path.resolve(__dirname, '../src/main/resources/static/'),
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
ws: true,
changeOrigin: true,
},
},
},
};
8 changes: 4 additions & 4 deletions src/main/java/wooteco/subway/DataLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
@Component
@Profile("!test")
public class DataLoader implements CommandLineRunner {
private StationDao stationDao;
private LineDao lineDao;
private SectionDao sectionDao;
private MemberDao memberDao;
private final StationDao stationDao;
private final LineDao lineDao;
private final SectionDao sectionDao;
private final MemberDao memberDao;

public DataLoader(StationDao stationDao, LineDao lineDao, SectionDao sectionDao, MemberDao memberDao) {
this.stationDao = stationDao;
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/wooteco/subway/SubwayApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
@SpringBootApplication
public class SubwayApplication {

public static void main(String[] args) {
SpringApplication.run(SubwayApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(SubwayApplication.class, args);
}

}
13 changes: 13 additions & 0 deletions src/main/java/wooteco/subway/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package wooteco.subway;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*").allowedOriginPatterns("*");
}
}
Loading