[Practice] 사용자 관련 API 만들기 (6)
2021. 4. 18. 23:44ㆍSpring/Practice
1. 문제
- 회원 로그인 히스토리 기능을 구현하는 API
2. 풀이
- schema.sql
...
create table LOGS
(
ID BIGINT auto_increment primary key,
TEXT CLOB,
REG_DATE TIMESTAMP
);
- ApiLoginController.java
package com.example.jpa.sample.user.controller;
import com.example.jpa.sample.common.exception.BizException;
import com.example.jpa.sample.common.model.ResponseResult;
import com.example.jpa.sample.notice.model.ResponseError;
import com.example.jpa.sample.user.entity.User;
import com.example.jpa.sample.user.model.UserLogin;
import com.example.jpa.sample.user.model.UserLoginToken;
import com.example.jpa.sample.user.service.UserService;
import com.example.jpa.sample.util.JwtUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RequiredArgsConstructor
@RestController
public class ApiLoginController {
private final UserService userService;
// 문제 6
@PostMapping("/api/login")
public ResponseEntity<?> login(@RequestBody @Valid UserLogin userLogin, Errors errors) {
if(errors.hasErrors()) {
return ResponseResult.fail("입력값이 정확하지 않습니다.", ResponseError.of(errors.getAllErrors()));
}
User user = null;
try {
user = userService.login(userLogin);
} catch(BizException e) {
return ResponseResult.fail(e.getMessage());
}
UserLoginToken userLoginToken = JwtUtils.createToken(user);
if(userLoginToken == null) {
return ResponseResult.fail("JWT 생성에 실패하였습니다.");
}
return ResponseResult.success(userLoginToken);
}
}
- UserService.java
package com.example.jpa.sample.user.service;
import com.example.jpa.sample.board.model.ServiceResult;
import com.example.jpa.sample.user.entity.User;
import com.example.jpa.sample.user.model.UserLogCount;
import com.example.jpa.sample.user.model.UserLogin;
import com.example.jpa.sample.user.model.UserNoticeCount;
import com.example.jpa.sample.user.model.UserSummary;
import java.util.List;
public interface UserService {
...
User login(UserLogin userLogin);
}
- UserServiceImpl.java
package com.example.jpa.sample.user.service;
import com.example.jpa.sample.board.model.ServiceResult;
import com.example.jpa.sample.common.exception.BizException;
import com.example.jpa.sample.user.entity.User;
import com.example.jpa.sample.user.entity.UserInterest;
import com.example.jpa.sample.user.model.*;
import com.example.jpa.sample.user.repository.UserCustomRepository;
import com.example.jpa.sample.user.repository.UserInterestRepository;
import com.example.jpa.sample.user.repository.UserRepository;
import com.example.jpa.sample.util.PasswordUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@RequiredArgsConstructor
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final UserCustomRepository userCustomRepository;
private final UserInterestRepository userInterestRepository;
...
@Override
public User login(UserLogin userLogin) {
Optional<User> optionalUser = userRepository.findByEmail(userLogin.getEmail());
if(!optionalUser.isPresent()) {
throw new BizException("회원 정보가 존재하지 않습니다.");
}
User user = optionalUser.get();
if(PasswordUtils.equalPassword(userLogin.getPassword(), user.getPassword())) {
throw new BizException("일치하는 정보가 없습니다."); // 정보 자체를 정확히 안알려주는 것도 보안의 일종
}
return user;
}
}
- ApiLoginController.java
package com.example.jpa.sample.user.controller;
import com.example.jpa.sample.common.exception.BizException;
import com.example.jpa.sample.common.model.ResponseResult;
import com.example.jpa.sample.notice.model.ResponseError;
import com.example.jpa.sample.user.entity.User;
import com.example.jpa.sample.user.model.UserLogin;
import com.example.jpa.sample.user.model.UserLoginToken;
import com.example.jpa.sample.user.service.UserService;
import com.example.jpa.sample.util.JwtUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RequiredArgsConstructor
@RestController
public class ApiLoginController {
private final UserService userService;
// 문제 6
@PostMapping("/api/login")
public ResponseEntity<?> login(@RequestBody @Valid UserLogin userLogin, Errors errors) {
if(errors.hasErrors()) {
return ResponseResult.fail("입력값이 정확하지 않습니다.", ResponseError.of(errors.getAllErrors()));
}
User user = null;
try {
user = userService.login(userLogin);
} catch(BizException e) {
return ResponseResult.fail(e.getMessage());
}
UserLoginToken userLoginToken = JwtUtils.createToken(user);
if(userLoginToken == null) {
return ResponseResult.fail("JWT 생성에 실패하였습니다.");
}
return ResponseResult.success(userLoginToken);
}
}
- MainApplication.java
package com.example.jpa.sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@EnableAspectJAutoProxy // aop 동작 설정
@SpringBootApplication
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
- Logs.java
package com.example.jpa.sample.logs.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
@Entity
public class Logs {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String text;
@Column
private LocalDateTime regDate;
}
- LogService.java
package com.example.jpa.sample.logs.service;
public interface LogService {
void add(String text);
}
- LogServiceImpl.java
package com.example.jpa.sample.logs.service;
import com.example.jpa.sample.logs.entity.Logs;
import com.example.jpa.sample.logs.repository.LogsRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@RequiredArgsConstructor
@Service
public class LogServiceImpl implements LogService {
private final LogsRepository logsRepository;
@Override
public void add(String text) {
logsRepository.save(Logs.builder()
.text(text)
.regDate(LocalDateTime.now())
.build());
}
}
- LogsRepository.java
package com.example.jpa.sample.logs.repository;
import com.example.jpa.sample.logs.entity.Logs;
import org.springframework.data.jpa.repository.JpaRepository;
public interface LogsRepository extends JpaRepository<Logs, Long> {
}
- UserLogin.java (@ToString 어노테이션 추가)
package com.example.jpa.sample.user.model;
import lombok.*;
import javax.validation.constraints.NotBlank;
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class UserLogin {
@NotBlank(message = "이메일 항목은 필수입니다.")
private String email;
@NotBlank(message = "비밀번호 항목은 필수입니다.")
private String password;
}
- LoginLogger.java
package com.example.jpa.sample.common.aop;
import com.example.jpa.sample.logs.service.LogService;
import com.example.jpa.sample.user.entity.User;
import com.example.jpa.sample.user.model.UserLogin;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j // 로그 찍어보는 용도로 사용
@RequiredArgsConstructor
@Aspect
@Component
public class LoginLogger {
private final LogService logService;
@Around("execution(* com.example.jpa.sample..*.*Service*.*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("#################################");
log.info("서비스 호출 전");
Object result = joinPoint.proceed();
// joinPoint.getArgs() : 서비스 호출시 넘기는 파라미터
// joinPoint.getSignature() : 메시지 정보 (ex. 메서드의 경우 getDeclaringTypeName(), getName() 사용)
if("login".equals(joinPoint.getSignature().getName())) {
StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append("함수명: " + joinPoint.getSignature().getDeclaringTypeName() + ", " + joinPoint.getSignature().getName());
sb.append("\n");
sb.append("매개변수: ");
Object[] args = joinPoint.getArgs();
if(args != null && args.length > 0) {
for(Object o : args) {
if(o instanceof UserLogin) {
// String email = ((UserLogin)o).getEmail();
// String password = ((UserLogin)o).getPassword();
sb.append(((UserLogin)o).toString()); // @ToString
sb.append("리턴값: " + ((User)result).toString());
}
}
logService.add(sb.toString());
log.info(sb.toString());
}
}
log.info("#################################");
log.info("서비스 호출 후");
return result;
}
}
728x90
'Spring > Practice' 카테고리의 다른 글
[Practice] 사용자 관련 API 만들기 (8) (0) | 2021.04.19 |
---|---|
[Practice] 사용자 관련 API 만들기 (7) (0) | 2021.04.19 |
[Practice] 사용자 관련 API 만들기 (5) (0) | 2021.04.17 |
[Practice] 사용자 관련 API 만들기 (4) (0) | 2021.04.17 |