Skip to content

Commit

Permalink
Merge pull request #168 from urinaner/feature/163
Browse files Browse the repository at this point in the history
[BE] User 기본 CRUD 기능 구현
  • Loading branch information
urinaner authored Nov 24, 2024
2 parents f79377c + b3e177e commit 0246d2e
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 32 deletions.
11 changes: 11 additions & 0 deletions backend/backup.sql
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,14 @@ CREATE TABLE IF NOT EXISTS `board` (
KEY `FK_board_department` (`department_id`),
CONSTRAINT `FK_board_department` FOREIGN KEY (`department_id`) REFERENCES `Department` (`department_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- User 테이블 생성
CREATE TABLE IF NOT EXISTS `user` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`student_id` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`major` varchar(255) DEFAULT NULL,
`role` varchar(255) DEFAULT NULL,
'phone' varchar(255) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

@RequiredArgsConstructor
public enum AdminExceptionType implements BaseExceptionType {
NOT_FOUND_ADMIN(NOT_FOUND, "계정을 찾을 수 없습니다"),
ALREADY_EXIST_LOGIN_ID(NOT_FOUND, "이미 존재하는 로그인 ID입니다"),
NOT_VALID_PASSWORD(NOT_FOUND, "비밀번호가 유효하지 않습니다"),
INVALID_ACCESS_TOKEN(NOT_FOUND, "토큰이 유효하지 않습니다"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public ResponseEntity<Long> createSeminar(@RequestBody SeminarReqDto seminarReqD
return new ResponseEntity<>(seminarId, HttpStatus.OK);
}

@Operation(summary = "모든 세미나 조회 API", description = "모든 세미나의 리스트 반환")
@Operation(summary = "단일 세미나 조회 API", description = "단일 세미나의 리스트 반환")
@GetMapping("/{seminarId}")
public ResponseEntity<SeminarResDto> getSeminar(@PathVariable(name = "seminarId") Long seminarId) {
SeminarResDto seminarResDto = seminarService.getSeminar(seminarId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package org.example.backend.user.controller;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.example.backend.admin.domain.dto.SignInReqDto;
import org.example.backend.common.exception.dto.ResponseDto;
import org.example.backend.user.domain.dto.UserReqDto;
import org.example.backend.user.domain.dto.UserResDto;
import org.example.backend.user.service.UserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -13,14 +23,40 @@
@RequiredArgsConstructor
@RequestMapping("/api/user")
public class UserController {

private final UserService userService;
@PostMapping("/join")
public ResponseEntity<String> joinProcess(@RequestBody SignInReqDto joinDTO) {
String token = userService.joinProcess(joinDTO);

@PostMapping("/login")
public ResponseEntity<String> loginProcess(@RequestBody SignInReqDto joinDTO) {
String token = userService.loginProcess(joinDTO);

return ResponseEntity.ok()
.header("Authorization", "Bearer " + token)
.body("ok");
}

@PostMapping
public ResponseEntity<Long> createUser(@RequestBody UserReqDto userReqDto) {
Long userId = userService.saveUser(userReqDto);
return new ResponseEntity<>(userId, HttpStatus.OK);
}

@GetMapping
public ResponseDto<List<UserResDto>> getAllUsers(Pageable pageable) {
Page<UserResDto> userList = userService.getAllUsers(pageable);
return ResponseDto.ok(userList.getNumber(), userList.getTotalPages(), userList.getContent());
}

@PostMapping("/{userId}")
public ResponseEntity<UserResDto> updateUser(@PathVariable(name = "userId") Long userId,
@RequestBody UserReqDto userReqDto) {
UserResDto userResDto = userService.updateUser(userId, userReqDto);
return new ResponseEntity<>(userResDto, HttpStatus.OK);
}

@DeleteMapping("/{userId}")
public ResponseEntity<Void> deleteUser(@PathVariable(name = "userId") Long userId) {
userService.deleteUser(userId);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.example.backend.user.domain.dto;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserReqDto {

private String studentId;

private String name;

private String major;

private String phoneN;

@Builder
private UserReqDto(String studentId, String name, String major, String phoneN) {
this.studentId = studentId;
this.name = name;
this.major = major;
this.phoneN = phoneN;
}

public static UserReqDto of(String studentId, String name, String major, String phoneN) {
return UserReqDto.builder()
.studentId(studentId)
.name(name)
.major(major)
.phoneN(phoneN)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.example.backend.user.domain.dto;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.example.backend.user.domain.entity.User;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserResDto {

private Long id;

private String studentId;

private String name;

private String major;

private String phoneN;

@Builder
private UserResDto(Long id, String studentId, String name, String major, String phoneN) {
this.id = id;
this.studentId = studentId;
this.name = name;
this.major = major;
this.phoneN = phoneN;
}

public static UserResDto of(User user) {
return UserResDto.builder()
.id(user.getId())
.studentId(user.getStudentId())
.name(user.getName())
.major(user.getMajor())
.phoneN(user.getPhoneN())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
package org.example.backend.user.domain.entity;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.example.backend.reservation.domain.Reservation;
import org.example.backend.user.domain.dto.UserReqDto;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "user")
@Table(name = "users")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
@Column(name = "user_id", nullable = false)
private Long id;

@Column(name = "student_id", unique = true)
private String studentId;

@Column(name = "name")
private String name;

Expand All @@ -35,6 +35,29 @@ public class User {
@Column(name = "phone", unique = true)
private String phoneN;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Reservation> reservations = new ArrayList<>();
@Column(name = "role", nullable = false)
private String role = "USER";

@Builder
private User(String studentId, String name, String major, String phoneN) {
this.studentId = studentId;
this.name = name;
this.major = major;
this.phoneN = phoneN;
}

public static User of(UserReqDto dto) {
return User.builder()
.studentId(dto.getStudentId())
.name(dto.getName())
.major(dto.getMajor())
.phoneN(dto.getPhoneN())
.build();
}

public void update(UserReqDto dto) {
this.name = dto.getName();
this.major = dto.getMajor();
this.phoneN = dto.getPhoneN();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.example.backend.user.exception;

import lombok.RequiredArgsConstructor;
import org.example.backend.common.exception.BaseException;
import org.example.backend.common.exception.BaseExceptionType;

@RequiredArgsConstructor
public class UserException extends BaseException {

private final UserExceptionType exceptionType;

@Override
public BaseExceptionType exceptionType() {
return exceptionType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.example.backend.user.exception;

import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.NOT_FOUND;

import lombok.RequiredArgsConstructor;
import org.example.backend.common.exception.BaseExceptionType;
import org.springframework.http.HttpStatus;

@RequiredArgsConstructor
public enum UserExceptionType implements BaseExceptionType {

NOT_FOUND_USER(NOT_FOUND, "사용자를 찾을 수 없습니다"),
DUPLICATE_PHONE(BAD_REQUEST, "전화번호가 이미 존재합니다."),
REQUIRED_NAME(BAD_REQUEST, "이름은 필수 입력값입니다."),
REQUIRED_STUDENT_ID(BAD_REQUEST, "학번은 필수 입력값입니다.")
;

private final HttpStatus httpStatus;
private final String errorMessage;

@Override
public HttpStatus httpStatus() {
return httpStatus;
}

@Override
public String errorMessage() {
return errorMessage;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.example.backend.user.repository;

import org.example.backend.user.domain.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,87 @@
package org.example.backend.user.service;

import static org.example.backend.user.exception.UserExceptionType.NOT_FOUND_USER;

import org.example.backend.user.domain.entity.User;
import org.springframework.data.domain.Pageable;
import lombok.RequiredArgsConstructor;
import org.example.backend.admin.domain.dto.SignInReqDto;
import org.example.backend.admin.exception.AdminException;
import org.example.backend.admin.exception.AdminExceptionType;
import org.example.backend.jwt.JWTUtil;
import org.example.backend.user.domain.dto.UserReqDto;
import org.example.backend.user.domain.dto.UserResDto;
import org.example.backend.user.exception.UserException;
import org.example.backend.user.exception.UserExceptionType;
import org.example.backend.user.repository.UserRepository;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yj.sejongauth.controller.Sj;
import org.yj.sejongauth.domain.SjProfile;

@RequiredArgsConstructor
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {

private final UserRepository userRepository;

private final Sj sj;
private final JWTUtil jwtUtil;
public String joinProcess(SignInReqDto joinDTO) {

@Transactional
public String loginProcess(SignInReqDto joinDTO) {
try {
SjProfile sjProfile = sj.login(joinDTO.getLoginId(), joinDTO.getPassword());
String token = jwtUtil.createJwt(sjProfile.getName(), "USER", 60 * 60 * 10L);
UserReqDto userReqDto = UserReqDto.builder()
.name(sjProfile.getName())
.studentId(sjProfile.getStudentCode())
.major(sjProfile.getMajor())
.build();
saveUser(userReqDto);
return token;
} catch (RuntimeException e) {
throw new AdminException(AdminExceptionType.NOT_FOUND_ADMIN);
throw new UserException(NOT_FOUND_USER);
}
}

@Transactional
public Long saveUser(UserReqDto userReqDto) {
validateRequiredFields(userReqDto);
User user = User.of(userReqDto);
User savedUser = userRepository.save(user);
return savedUser.getId();
}

private void validateRequiredFields(UserReqDto userReqDto) {
if (userReqDto.getName() == null || userReqDto.getName().isEmpty()) {
throw new UserException(UserExceptionType.REQUIRED_NAME);
}
if (userReqDto.getStudentId() == null || userReqDto.getStudentId().isEmpty()) {
throw new UserException(UserExceptionType.REQUIRED_STUDENT_ID);
}
}

public Page<UserResDto> getAllUsers(Pageable pageable) {
return userRepository.findAll(pageable)
.map(UserResDto::of);
}

@Transactional
public UserResDto updateUser(Long userId, UserReqDto userReqDto) {
User user = findUserById(userId);
user.update(userReqDto);
return UserResDto.of(user);
}

@Transactional
public void deleteUser(Long userId) {
User user = findUserById(userId);
userRepository.delete(user);
}

private User findUserById(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new UserException(NOT_FOUND_USER));
}
}
Loading

0 comments on commit 0246d2e

Please sign in to comment.