Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
8d585d2
test: ๋…ธ์„  ์ƒ์„ฑ ํŒŒ๋ผ๋ฏธํ„ฐ ์†Œ์š”์‹œ๊ฐ„ ์ •๋ณด ์ถ”๊ฐ€
cyPark95 Mar 14, 2023
6053e33
fix: ์ถ”๊ฐ€ ์šด์ž„ ์š”๊ธˆ ๊ณ„์‚ฐ ์ˆ˜์ •
cyPark95 Mar 14, 2023
0ae3383
docs: 3๋‹จ๊ณ„ ์š”๊ตฌ์‚ฌํ•ญ ์ •๋ฆฌ
cyPark95 Mar 14, 2023
b0fa458
test: ๋…ธ์„ ๋ณ„ ์ถ”๊ฐ€ ์š”๊ธˆ ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
cyPark95 Mar 14, 2023
6cf1b3f
test: ๋…ธ์„ ๋ณ„ ์ถ”๊ฐ€ ์š”๊ธˆ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
cyPark95 Mar 14, 2023
82a22f3
feat: ๋…ธ์„ ๋ณ„ ์ถ”๊ฐ€ ์š”๊ธˆ ๊ตฌํ˜„
cyPark95 Mar 15, 2023
4588aa8
fix: ๋…ธ์„  ์ €์žฅ ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆ˜์ •
cyPark95 Mar 15, 2023
63e3a34
test: ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ์—ฐ๋ น๋ณ„ ์š”๊ธˆ ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
cyPark95 Mar 15, 2023
09d60fa
test: ์—ฐ๋ น๋ณ„ ์š”๊ธˆ ํ• ์ธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
cyPark95 Mar 15, 2023
c060b4c
feat: ์—ฐ๋ น๋ณ„ ์š”๊ธˆ ํ• ์ธ ๊ตฌํ˜„
cyPark95 Mar 15, 2023
488829e
test: ๊ฒฝ๋กœ ์กฐํšŒ ์—ฐ๋ น๋ณ„ ์š”๊ธˆ ํ• ์ธ ์ ์šฉ ํ…Œ์ŠคํŠธ
cyPark95 Mar 15, 2023
77e9f80
feat: ๊ฒฝ๋กœ ์กฐํšŒ ์—ฐ๋ น๋ณ„ ์š”๊ธˆ ํ• ์ธ ์ ์šฉ
cyPark95 Mar 15, 2023
e6c71a9
feat: ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ์ •๋ณด ๋‚˜์ด ์ถ”๊ฐ€
cyPark95 Mar 15, 2023
ff5085c
feat: ๋กœ๊ทธ์ธ ํ•„์ˆ˜ ์—ฌ๋ถ€ ์ถ”๊ฐ€
cyPark95 Mar 15, 2023
d337164
feat: ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ํ™•์ธ ์ถ”๊ฐ€
cyPark95 Mar 15, 2023
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,12 @@

- ๊ฒฝ๋กœ ์กฐํšŒ ๊ฒฐ๊ณผ์— ์š”๊ธˆ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜์„ธ์š”.
- ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ (์ˆ˜์ •) -> ๋ฌธ์„œํ™” -> ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ˆœ์œผ๋กœ ์ง„ํ–‰ํ•˜์„ธ์š”.
- ๊ฐœ๋ฐœ ํ๋ฆ„์„ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ปค๋ฐ‹์„ ์ž‘์€ ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„์–ด ๊ตฌํ˜„ํ•ด๋ณด์„ธ์š”.

## ๐Ÿš€ 3๋‹จ๊ณ„ - ์š”๊ธˆ ์ •์ฑ… ์ถ”๊ฐ€

### ์š”๊ตฌ์‚ฌํ•ญ

- ์ถ”๊ฐ€๋œ ์š”๊ธˆ ์ •์ฑ…์„ ๋ฐ˜์˜ํ•˜์„ธ์š”.
- ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ ๋ณ€๊ฒฝ -> ๋ฌธ์„œํ™” ๋ณ€๊ฒฝ -> ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ˆœ์œผ๋กœ ์ง„ํ–‰ํ•˜์„ธ์š”.
- ๊ฐœ๋ฐœ ํ๋ฆ„์„ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ปค๋ฐ‹์„ ์ž‘์€ ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„์–ด ๊ตฌํ˜„ํ•ด๋ณด์„ธ์š”.
17 changes: 14 additions & 3 deletions src/main/java/nextstep/member/application/JwtTokenProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public class JwtTokenProvider {
@Value("${security.jwt.token.expire-length}")
private long validityInMilliseconds;

public String createToken(String principal, List<String> roles) {
public String createToken(final String principal,
final int age,
final List<String> roles) {
Claims claims = Jwts.claims().setSubject(principal);
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
Expand All @@ -24,16 +26,25 @@ public String createToken(String principal, List<String> roles) {
.setIssuedAt(now)
.setExpiration(validity)
.claim("roles", roles)
.claim("age", age)
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}

public String getPrincipal(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
return getClaims(token).getSubject();
}

public int getAge(final String token) {
return getClaims(token).get("age", Integer.class);
}

public List<String> getRoles(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().get("roles", List.class);
return getClaims(token).get("roles", List.class);
}

private Claims getClaims(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
}

public boolean validateToken(String token) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/nextstep/member/application/TokenService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public TokenService(MemberService memberService, JwtTokenProvider jwtTokenProvid
public TokenResponse createToken(String email, String password) {
Member member = memberService.login(email, password);

String token = jwtTokenProvider.createToken(member.getId().toString(), member.getRoles());
String token = jwtTokenProvider.createToken(member.getId().toString(), member.getAge(), member.getRoles());

return new TokenResponse(token);
}
Expand All @@ -32,7 +32,7 @@ public TokenResponse createGithubToken(String code) {

Member member = memberService.createOrFindMember(githubProfile.getEmail());

String token = jwtTokenProvider.createToken(member.getId().toString(), member.getRoles());
String token = jwtTokenProvider.createToken(member.getId().toString(), member.getAge(), member.getRoles());

return new TokenResponse(token);
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/nextstep/member/domain/AnonymousMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package nextstep.member.domain;

import java.util.List;

public class AnonymousMember extends LoginMember {

public AnonymousMember() {
super(-1L, 0, List.of(RoleType.ROLE_ANONYMOUS.name()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthenticationPrincipal {

boolean required() default true;
}
10 changes: 9 additions & 1 deletion src/main/java/nextstep/member/domain/LoginMember.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@

public class LoginMember {
private Long id;
private int age;
private List<String> roles;

public LoginMember(Long id, List<String> roles) {
public LoginMember(final Long id,
final int age,
final List<String> roles) {
this.id = id;
this.age = age;
this.roles = roles;
}

public Long getId() {
return id;
}

public int getAge() {
return age;
}

public List<String> getRoles() {
return roles;
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/nextstep/member/domain/RoleType.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public enum RoleType {
ROLE_ADMIN,
ROLE_MEMBER
ROLE_MEMBER,
ROLE_ANONYMOUS
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package nextstep.member.ui;

import nextstep.member.application.JwtTokenProvider;
import nextstep.member.domain.AnonymousMember;
import nextstep.member.domain.AuthenticationPrincipal;
import nextstep.member.domain.LoginMember;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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 java.util.List;
import java.util.Objects;

@Component
public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver {
Expand All @@ -27,15 +30,23 @@ public boolean supportsParameter(MethodParameter parameter) {

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String authorization = webRequest.getHeader("Authorization");

final boolean required = Objects.requireNonNull(parameter.getParameterAnnotation(AuthenticationPrincipal.class)).required();
final String authorization = webRequest.getHeader("Authorization");

if (!required && !StringUtils.hasText(authorization)) {
return new AnonymousMember();
}

if (!"bearer".equalsIgnoreCase(authorization.split(" ")[0])) {
throw new AuthenticationException();
}
String token = authorization.split(" ")[1];

Long id = Long.parseLong(jwtTokenProvider.getPrincipal(token));
int age = jwtTokenProvider.getAge(token);
List<String> roles = jwtTokenProvider.getRoles(token);

return new LoginMember(id, roles);
return new LoginMember(id, age, roles);
}
}
2 changes: 1 addition & 1 deletion src/main/java/nextstep/subway/applicaion/LineService.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public LineService(LineRepository lineRepository, StationService stationService)

@Transactional
public LineResponse saveLine(final LineRequest request) {
final Line line = lineRepository.save(new Line(request.getName(), request.getColor()));
final Line line = lineRepository.save(new Line(request.getName(), request.getColor(), request.getAddFare()));
if (isValidSaveRequest(request)) {
Station upStation = stationService.findById(request.getUpStationId());
Station downStation = stationService.findById(request.getDownStationId());
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/nextstep/subway/applicaion/PathService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nextstep.subway.applicaion;

import nextstep.member.domain.LoginMember;
import nextstep.subway.applicaion.dto.PathResponse;
import nextstep.subway.applicaion.dto.PathType;
import nextstep.subway.domain.*;
Expand All @@ -17,13 +18,14 @@ public PathService(LineService lineService, StationService stationService) {
this.stationService = stationService;
}

public PathResponse findPath(final Long source,
public PathResponse findPath(final LoginMember member,
final Long source,
final Long target,
final PathType type) {
Station upStation = stationService.findById(source);
Station downStation = stationService.findById(target);
List<Line> lines = lineService.findLines();
SubwayMap subwayMap = new SubwayMap(lines);
SubwayMap subwayMap = new SubwayMap(lines, new AgeDiscountPolicy(member));
Path path = subwayMap.findPath(upStation, downStation, type);
return PathResponse.of(path);
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/nextstep/subway/applicaion/dto/LineRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class LineRequest {
private Long downStationId;
private int distance;
private int duration;
private int addFare;

public String getName() {
return name;
Expand All @@ -31,4 +32,8 @@ public int getDistance() {
public int getDuration() {
return duration;
}

public int getAddFare() {
return addFare;
}
}
58 changes: 58 additions & 0 deletions src/main/java/nextstep/subway/domain/AgeDiscountPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package nextstep.subway.domain;

import nextstep.member.domain.LoginMember;

import static nextstep.member.domain.RoleType.ROLE_ANONYMOUS;

public class AgeDiscountPolicy implements DiscountPolicy {

public static final int DEDUCTION = 350;

public static final double CHILD_DISCOUNT = 0.5;
public static final double TEENAGER_DISCOUNT = 0.8;

public static final int CHILD_AGE = 6;
public static final int TEENAGER_AGE = 13;
public static final int ADULT_AGE = 19;

private final LoginMember member;

public AgeDiscountPolicy(LoginMember member) {
this.member = member;
}

@Override
public int calculator(final int fare) {
if (member.getRoles().contains(ROLE_ANONYMOUS.name())) {
return fare;
}

if (member.getAge() < 1) {
throw new IllegalArgumentException("๋‚˜์ด๋Š” 0 ์ดํ•˜์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}

return getDiscountFare(fare, member.getAge());
}

private int getDiscountFare(final int fare, final int age) {
if (isTeenager(age)) {
return calculateDiscountFare(fare, TEENAGER_DISCOUNT);
} else if (isChild(age)) {
return calculateDiscountFare(fare, CHILD_DISCOUNT);
}

return fare;
}

private boolean isChild(final int age) {
return age >= CHILD_AGE && age < TEENAGER_AGE;
}

private boolean isTeenager(final int age) {
return age >= TEENAGER_AGE && age < ADULT_AGE;
}

private int calculateDiscountFare(final int fare, final double teenagerDiscount) {
return (int) ((fare - DEDUCTION) * teenagerDiscount + DEDUCTION);
}
}
6 changes: 6 additions & 0 deletions src/main/java/nextstep/subway/domain/DiscountPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package nextstep.subway.domain;

public interface DiscountPolicy {

int calculator(int fare);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public int calculator(final int distance) {

private int calculateOverFare(final int distance,
final int chargeDistance) {
return (int) ((Math.ceil((distance - 1d) / chargeDistance) + 1) * ADDITIONAL_FARE);
return (((distance - 1) / chargeDistance) + 1) * ADDITIONAL_FARE;
}
}
14 changes: 13 additions & 1 deletion src/main/java/nextstep/subway/domain/Line.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@ public class Line {
private Long id;
private String name;
private String color;
private int addFare;

@Embedded
private Sections sections = new Sections();

public Line() {
}

public Line(String name, String color) {
public Line(final String name, final String color) {
this(name, color, 0);
}

public Line(final String name,
final String color,
final int addFare) {
this.name = name;
this.color = color;
this.addFare = addFare;
}

public Long getId() {
Expand All @@ -34,6 +42,10 @@ public String getColor() {
return color;
}

public int getAddFare() {
return addFare;
}

public List<Section> getSections() {
return sections.getSections();
}
Expand Down
26 changes: 22 additions & 4 deletions src/main/java/nextstep/subway/domain/Path.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package nextstep.subway.domain;

import java.util.List;
import java.util.Optional;

public class Path {
private Sections sections;
private FarePolicy farePolicy;
private Optional<DiscountPolicy> discountPolicy;

private int addFare;
private int minDistance;

public Path(final Sections sections,
final FarePolicy farePolicy) {
this(sections, farePolicy, 0);
final FarePolicy farePolicy,
final DiscountPolicy discountPolicy,
final int addFare) {
this(sections, farePolicy, discountPolicy, addFare ,0);
}

public Path(final Sections sections,
final FarePolicy farePolicy,
final DiscountPolicy discountPolicy,
final int addFare,
final int minDistance) {
this.sections = sections;
this.farePolicy = farePolicy;
this.discountPolicy = Optional.ofNullable(discountPolicy);
this.addFare = addFare;
this.minDistance = minDistance;
}

Expand All @@ -39,8 +48,17 @@ public List<Station> getStations() {

public int getFare() {
if (minDistance > 0) {
return farePolicy.calculator(minDistance);
return calculateFare(minDistance);
}
return farePolicy.calculator(sections.totalDistance());
return calculateFare(sections.totalDistance());
}

private int calculateFare(final int minDistance) {
return getDiscountFare(farePolicy.calculator(minDistance) + addFare);
}

private int getDiscountFare(final int fare) {
return discountPolicy.map(policy -> policy.calculator(fare)).orElse(fare);

}
}
Loading