Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
18b8ea6
1-2-3단계 커밋
Jun 24, 2024
ac9d564
수정
Jun 24, 2024
0194a4a
삼단계 누락 추가
Jun 25, 2024
58bb75f
리뷰 반영
Jun 30, 2024
84fb7a1
리뷰 반영
Jun 30, 2024
f53da3a
리뷰 반영2
Jun 30, 2024
e6ea575
jpa 4,5,6
Jul 2, 2024
6f3270b
jpa modified
Jul 2, 2024
f450b0f
7,8 단계
Jul 8, 2024
f5d81d5
7단계 수정
Jul 8, 2024
0ced918
7 retry
Jul 8, 2024
9552f5f
add: ci.yml add
Jul 21, 2024
bd79489
ci : test
Jul 21, 2024
5469490
ci : core branch add
Jul 21, 2024
a43cc9e
ci : core branch add after -> test
Jul 21, 2024
4206a81
ci : test 0.0.1
Jul 21, 2024
9915ae8
ci : test 0.0.2
Jul 21, 2024
dab6831
ci > ci/cd
Jul 21, 2024
2bf3d7b
ci > ci/cd.001
Jul 21, 2024
ea30f53
ci > ci/cd.002 -x test
Jul 21, 2024
0c12843
ci > ci/cd.003 key update
Jul 21, 2024
41d7316
ci > ci/cd.004 ci/cd check
Jul 21, 2024
bf448cc
ci > ci/cd.005 ci/cd check:main->gotobill-core
Jul 21, 2024
aefd93c
ci > ci/cd.006 ci/cd check:main->gotobill-core
Jul 21, 2024
5db14e0
ci > ci/cd.007 배포 test
Jul 21, 2024
9d5f106
ci > ci/cd.008 kill now process and run
Jul 21, 2024
aa081a4
ci > ci/cd.009 add: after nohup sleep 10
Jul 21, 2024
be84bd3
ci > ci/cd.010 -: after nohup sleep 10
Jul 21, 2024
59b528c
ci > ci/cd.011 add: kill process
Jul 21, 2024
3dec885
ci > ci/cd.012 add: kill process before pull
Jul 21, 2024
05b16f2
ci > ci/cd.013 add: kill process before pull
Jul 21, 2024
ffb620e
ci > ci/cd.014 add: kill process before pull
Jul 21, 2024
972306f
ci > ci/cd.015 add: kill process before pull
Jul 21, 2024
b5ca92a
ci > ci/cd.016 add: kill process before pull
Jul 21, 2024
c9771d3
ci > ci/cd.017 last
Jul 21, 2024
4be8a68
ci > ci/cd.018
Jul 21, 2024
f4ede7d
ci > ci/cd.019
Jul 21, 2024
8aa3c81
ci > ci/cd.20
Jul 21, 2024
4599618
ci > ci/cd.21
Jul 21, 2024
2309e53
ci > ci/cd.22
Jul 21, 2024
38e646a
ci > ci/cd.23
Jul 21, 2024
dc4aee2
ci > ci/cd.24
Jul 21, 2024
320e50b
ci > ci/cd.25
Jul 21, 2024
abc990a
ci > ci/cd.26
Jul 21, 2024
fccb995
ci > ci/cd.27
Jul 21, 2024
dabedb8
ci > ci/cd.28
Jul 21, 2024
5821086
add: nginx 30
Jul 22, 2024
fe59f04
add: nginx 30
Jul 22, 2024
565bc8d
add: nginx 31
Jul 22, 2024
e4959af
add: nginx 32
Jul 22, 2024
b1cb56f
add: nginx 33
Jul 22, 2024
db17df5
add: nginx 34
Jul 22, 2024
cdbf9b2
add: nginx 35
Jul 22, 2024
9755601
add docker
GoToBILL Aug 8, 2024
25fdc65
add docker :01
GoToBILL Aug 8, 2024
b2efc64
add docker :02
GoToBILL Aug 12, 2024
3efd6bd
add docker :03
GoToBILL Aug 12, 2024
80642c0
add docker :04
GoToBILL Aug 12, 2024
08a4470
add docker :05
GoToBILL Aug 12, 2024
4203c1a
add docker :06
GoToBILL Aug 12, 2024
d568742
add docker :07
GoToBILL Aug 12, 2024
5a3f2e8
add docker :08
GoToBILL Aug 12, 2024
39078a3
add docker :09
GoToBILL Aug 12, 2024
8373483
add docker :10
GoToBILL Aug 12, 2024
8d9dabe
add docker :11
GoToBILL Aug 12, 2024
31f5f98
add docker :12
GoToBILL Aug 12, 2024
2a2950f
add docker :13
GoToBILL Aug 12, 2024
496db22
add docker :14
GoToBILL Aug 12, 2024
0d264df
add docker :15
GoToBILL Aug 12, 2024
0f76376
add docker :16
GoToBILL Aug 12, 2024
fbae782
add docker :17
GoToBILL Aug 12, 2024
157de6d
add docker :18
GoToBILL Aug 12, 2024
df0350e
add docker :19
GoToBILL Aug 12, 2024
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
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:4.0.0'
implementation 'org.springframework.boot:spring-boot-starter'

implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.2'
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/auth/AuthConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package auth;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AuthConfig {

@Bean
public JwtUtils jwtUtils(@Value("${roomescape.auth.jwt.secret}") String secretKey) {
return new JwtUtils(secretKey);
}
}
7 changes: 7 additions & 0 deletions src/main/java/auth/JwtTokenMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package auth;

public record JwtTokenMember(
String name,
String role
) {
}
44 changes: 44 additions & 0 deletions src/main/java/auth/JwtUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package auth;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import roomescape.member.Member;

public class JwtUtils {

private final String secretKey;

public JwtUtils(String secretKey) {
this.secretKey = secretKey;
}

public String createToken(Member member){
return Jwts.builder()
.setSubject(member.getId().toString())
.claim("name", member.getName())
.claim("role", member.getRole())
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
.compact();
}

public JwtTokenMember extractToken(String token) {
Claims claims = Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes()))
.build()
.parseClaimsJws(token)
.getBody();
String name = claims.get("name", String.class);
String role = claims.get("role", String.class);
return new JwtTokenMember(name,role);
}
public Long decodeToken(String token) {
if (token == null) return null;
return Long.valueOf(Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes()))
.build()
.parseClaimsJws(token)
.getBody().getSubject());
}

}
33 changes: 33 additions & 0 deletions src/main/java/roomescape/AppConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package roomescape;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import roomescape.argumentResolver.LoginMemberArgumentResolver;
import roomescape.interceptor.AuthInterceptor;

import java.util.List;

@Configuration
public class AppConfig implements WebMvcConfigurer {

private final LoginMemberArgumentResolver loginMemberArgumentResolver;
private final AuthInterceptor authInterceptor;

public AppConfig(LoginMemberArgumentResolver loginMemberArgumentResolver, AuthInterceptor authInterceptor) {
this.loginMemberArgumentResolver = loginMemberArgumentResolver;
this.authInterceptor = authInterceptor;
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(loginMemberArgumentResolver);
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/admin/**");
}
}
31 changes: 31 additions & 0 deletions src/main/java/roomescape/Login/LoginController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package roomescape.Login;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import roomescape.member.MemberResponse;

@RestController
public class LoginController {
private final LoginService loginService;

public LoginController(LoginService loginService) {
this.loginService = loginService;
}

@PostMapping("/login")
public void login(@RequestBody LoginRequest loginRequest, HttpServletResponse response) {
String token = loginService.login(loginRequest); //토큰 받음
Cookie cookie = new Cookie("token", token);
cookie.setHttpOnly(true);
cookie.setPath("/");
response.addCookie(cookie);
}

@GetMapping("/login/check")
public MemberResponse loginCheck(
@CookieValue("token") String token) {
return loginService.checkLogin(token);
}
}
6 changes: 6 additions & 0 deletions src/main/java/roomescape/Login/LoginMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package roomescape.Login;

public record LoginMember(
Long id, String name, String email, String role
) {
}
7 changes: 7 additions & 0 deletions src/main/java/roomescape/Login/LoginRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package roomescape.Login;

public record LoginRequest(
String email,
String password
) {
}
44 changes: 44 additions & 0 deletions src/main/java/roomescape/Login/LoginService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package roomescape.Login;

import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import auth.JwtUtils;
import roomescape.member.Member;
import roomescape.member.MemberRepository;
import roomescape.member.MemberResponse;

import java.util.Optional;

@Service
public class LoginService {
private final MemberRepository memberRepository;
private final JwtUtils jwtUtils;

public LoginService(MemberRepository memberRepository, JwtUtils jwtUtils) {
this.memberRepository = memberRepository;
this.jwtUtils = jwtUtils;
}

public String login(LoginRequest loginRequest) {
try {
Optional<Member> member = memberRepository.findByEmailAndPassword(loginRequest.email(), loginRequest.password());
return jwtUtils.createToken(member.get());
} catch (DataAccessException e){
throw new IllegalArgumentException("로그인 정보가 일치하지 않습니다.");
}
}

public MemberResponse checkLogin(String token) {
Long userId = jwtUtils.decodeToken(token);
try {
Optional<Member> member = memberRepository.findById(userId);
return new MemberResponse(member.get().getId(), member.get().getName(), member.get().getEmail());
} catch (DataAccessException exception){
throw new IllegalArgumentException("존재하지 않는 회원입니다.");
}
}

public Member findByName(String name) {
return memberRepository.findByName(name).stream().findFirst().get();
}
}
3 changes: 3 additions & 0 deletions src/main/java/roomescape/RoomescapeApplication.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package roomescape;

import auth.AuthConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Import(AuthConfig.class)
public class RoomescapeApplication {
public static void main(String[] args) {
SpringApplication.run(RoomescapeApplication.class, args);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package roomescape.argumentResolver;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import roomescape.Login.LoginMember;
import roomescape.Login.LoginService;
import roomescape.member.Member;
import roomescape.member.MemberResponse;
import roomescape.member.MemberService;
import jakarta.servlet.http.Cookie;

import java.util.Arrays;

@Component
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
private final LoginService loginService;

public LoginMemberArgumentResolver(LoginService loginService) {
this.loginService = loginService;
}

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(LoginMember.class);
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

String token = Arrays.stream(request.getCookies())
.filter(cookie -> cookie.getName().equals("token"))
.findFirst()
.map(Cookie::getValue).orElseThrow(() -> new IllegalArgumentException("토큰이 없습니다."));

MemberResponse memberResponse = loginService.checkLogin(token);
Member member = loginService.findByName(memberResponse.getName());

return new LoginMember(member.getId(), member.getName(), member.getEmail(), member.getRole());
}

}
24 changes: 24 additions & 0 deletions src/main/java/roomescape/data/DataLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package roomescape.data;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import roomescape.member.Member;
import roomescape.member.MemberRepository;

@Profile("default")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Production용과 DataLoader와 Test용 TestDataLoader를 만드세요 라는 요구 사항이 있었는데, 저는 주어진 그대로 @Profile("Production") 라고 단순하게 접근했습니다.
그런데 병주님을 포함한 대부분의 분들이 @Profile("default") 라고 많이 작성해 주셨더라고요.
둘 다 큰 상관이 없는걸 까요? 이 부분 궁금해요!

@Component
public class DataLoader implements CommandLineRunner {

private final MemberRepository memberRepository;

public DataLoader(final MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

@Override
public void run(final String... args) throws Exception {
final Member member1 = memberRepository.save(new Member("어드민", "[email protected]", "password", "ADMIN"));
final Member member2 = memberRepository.save(new Member("브라운", "[email protected]", "password", "USER"));
}
}
59 changes: 59 additions & 0 deletions src/main/java/roomescape/data/TestDataLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package roomescape.data;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import roomescape.member.Member;
import roomescape.member.MemberRepository;
import roomescape.reservation.Reservation;
import roomescape.reservation.ReservationRepository;
import roomescape.theme.Theme;
import roomescape.theme.ThemeRepository;
import roomescape.time.Time;
import roomescape.time.TimeRepository;

@Profile("test")
@Component
public class TestDataLoader implements CommandLineRunner {

private final MemberRepository memberRepository;

private final ThemeRepository themeRepository;

private final TimeRepository timeRepository;

private final ReservationRepository reservationRepository;
Comment on lines +17 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런부분은 하나씩 공백이 있을 필요 없을 것 같아보입니다!
이외에도 불필요한 공백들이 보이는 것 같습니다:)


public TestDataLoader(final MemberRepository memberRepository,
final ThemeRepository themeRepository,
final TimeRepository timeRepository,
final ReservationRepository reservationRepository) {
this.memberRepository = memberRepository;
this.themeRepository = themeRepository;
this.timeRepository = timeRepository;
this.reservationRepository = reservationRepository;
}

@Override
public void run(final String... args) throws Exception {
final Member member1 = memberRepository.save(new Member("어드민", "[email protected]", "password", "ADMIN"));
final Member member2 = memberRepository.save(new Member("브라운", "[email protected]", "password", "USER"));

final Theme theme1 = themeRepository.save(new Theme("테마1", "테마1입니다."));
final Theme theme2 = themeRepository.save(new Theme("테마2", "테마2입니다."));
final Theme theme3 = themeRepository.save(new Theme("테마3", "테마3입니다."));

final Time time1 = timeRepository.save(new Time("10:00"));
final Time time2 = timeRepository.save(new Time("12:00"));
final Time time3 = timeRepository.save(new Time("14:00"));
final Time time4 = timeRepository.save(new Time("16:00"));
final Time time5 = timeRepository.save(new Time("18:00"));
final Time time6 = timeRepository.save(new Time("20:00"));

reservationRepository.save(new Reservation("어드민", "2024-03-01", member1, time1, theme1));
reservationRepository.save(new Reservation("어드민", "2024-03-01", member1, time2, theme2));
reservationRepository.save(new Reservation("어드민", "2024-03-01", member1, time3, theme3));

reservationRepository.save(new Reservation("브라운", "2024-03-01", member2, time4, theme1));
}
}
Loading