Archive: 2021

0

Spring Boot 게시판 만들기 5 - 모든 Post 가져오기

5. 모든 포스트 가져오기모든 포스트 가져오기 요청 처리하기BoardController.java @Controller@RequiredArgsConstructorpublic class BoardController { private final PostService postService; @GetMapping("/") public String board(Model model){ List<Post> posts = postService.getAllPost(); model.addAttribute("PostList", posts); return "board"; }} 모든 Post 가져오기 요청에 대한 테스트 코드 작성BoardControllerTest.java @WebMvcTestclass BoardControllerTest { @Autowired private MockMvc mockMvc; @MockBean private PostService postService; @Test @DisplayName("모든 Post를 가져온다.") public void board() throws Exception { List<Post> posts = new ArrayList<>(); posts.add(Post.builder() .id(1L) .title("test") .name("tester") .content("test") .writeTime(LocalDateTime.now()) .build() ); given(postService.getAllPost()).willReturn(posts); ResultActions resultActions = mockMvc.perform(get("/")); resultActions .andExpect(status().isOk()) .andDo(print()); verify(postService).getAllPost(); }} 데이터 조회@Service@RequiredArgsConstructorpublic class PostService { private final PostRepository postRepository; public Post addPost(Post newPost) { return postRepository.save(newPost); } public List<Post> getAllPost() { return postRepository.findAll(); }}

0

Spring Boot 게시판 만들기 4 - My SQL과 연동하기

4. My SQL과 연동의존성 추가My Sql과 연동하기 위해서는 Springboot프로젝트에 의존성을 추가해야 한다. build.gradle implementation 'mysql:mysql-connector-java' 데이터베이스 접속 설정하기application-mysql.yml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/[DB]?serverTimezone=UTC&characterEncoding=UTF-8 username: [DB 접속 Id] password: [DB 접송 Password] 접속 설정 가져오기

0

Spring Boot 게시판 만들기 3 - 게시글 작성하기

3. 새로운 Post 생성 요청 처리하기데이터를 저장하는 로직은 DB에 접근을 하기 때문에 다음과 같은 로직을 추가해 DB에 데이터들이 제대로 저장되는지 확인한다. 어플리케이션을 실핸한 후 http://localhost:8080/h2-console 를 통해 데이터 베이스에 접근할 수 있다. application.yml spring: h2: console: enabled: true path: /h2-console datasource: username: sa password: url: jdbc:h2:mem:testdb driver-class-name: org.h2.Driver /post경로로 post 요청이 들어올 경우 입력된 정보들이 제대로 들어왔는지 Validation을 진행하고 문제가 없을 경우 데이터를 저장한다. PostController.java @PostMapping("/post")public String creatNewPost(@Valid @ModelAttribute("postDto") PostDto postDto) { postService.addPost(postDto); return "redirect:/";} 생성 요청 테스트 코드 작성하기MockBean 추가하기

0

Spring Boot 게시판 만들기 2 - 게시글 작성페이지 만들기

2. 게시글 작성페이지 설계도메인 설계하기사용자로부터 게시글 제목, 작성자 이름, 게시글 내용과 게시글들을 구별해주기 위해 Id값과 게시글이 언제 작성되었는지 알기 위한 작성시간을 추가해 도메인을 만든다. Post.java @Entity@NoArgsConstructor@AllArgsConstructor@Builder@Getterpublic class Post { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotEmpty private String title; @NotEmpty private String name; @NotEmpty private String content; @NotNull private LocalDateTime writeTime;} DTO 작성하기사용자로부터 Form을 통해 title, name, content를 입력 받는다. Post 객체를 사용해 데이터를 전달받을 수 있지만 View로직이 추가되게 된다. Entity는 DB와 데이터를 주고 받는 객체이기에 DTO를 만들어 Entity를 View로직으로부터 분리해 추후 생길 수 있는 문제를 없애도록 한다.

0

Spring Boot 게시판 만들기 1 - 게시글 작성 페이지

1. 게시글 작성 페이지 만들기간단하게 게시글 제목, 사용자 이름, 게시글 내용 세가지만 입력 받는 폼을 만들 것이다. 게시글 작성페이지는 Bootstrap을 이용해 만들건데, BootsWatch의 Cosmo navbar가 마음에 들어 이것도 사용할 것이다. 먼저, Bootstrap 사이트에서 css, js, fonts를 다운 받고 BootsWatch사이트 Cosmo 페이지에서 custom.min.css을 다운 받은 후 springboot 프로젝트내의 resources/static위치에 폴더들은 넣는다. Bootstrap 사이트 : https://getbootstrap.com/docs/4.6/getting-started/introduction/Bootswatch 사이트 : https://bootswatch.com/

0

JPA 란?

JPA 란?객체를 이용해 DataBase 테이블을 다루기 위해 만들어진 ORM(Object Relation Mapping) 기술

0

레스토랑 예약 사이트 만들기 14 - 테이블 예약

패스트 캠퍼스에서 @RestController@RequiredArgsConstructorpublic class ReservationController { private final ReservationService reservationService; @GetMapping("/reservations") public List<Reservation> list(Authentication authentication){ Claims claims = (Claims) authentication.getPrincipal(); Long restaurantId = claims.get("restaurantId", Long.class);// Long restaurantId = 1004L; List<Reservation> reservations = reservationService.getReservations(restaurantId); return reservations; }} @WebMvcTest(ReservationController.class)class ReservationControllerTest { @Autowired private MockMvc mockMvc; @MockBean private ReservationService reservationService; @Test @DisplayName("예약목록을 가져온다.") public void list() throws Exception { String token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEwMDQsIm5hbWUiOiJPd25lciIsInJlc3RhdXJhbnRJZCI6MTAwNH0.cQTXhzTW48F5Nj3eXa80Y9J4OJryzFvoHtT8ELl4kTw"; ResultActions resultActions = mockMvc.perform(get("/reservations") .header("Authorization", "Bearer " + token)); resultActions .andExpect(status().isOk()); verify(reservationService).getReservations(1004L); }} @Service@RequiredArgsConstructorpublic class ReservationService { private final ReservationRepository reservationRepository; public List<Reservation> getReservations(Long restaurantId) { return reservationRepository.findAllByRestaurantId(restaurantId); }} class ReservationServiceTest { @Mock private ReservationRepository reservationRepository; private ReservationService reservationService; @BeforeEach public void setUp(){ MockitoAnnotations.openMocks(this); this.reservationService = new ReservationService(reservationRepository); } @Test @DisplayName("예약목록들을 가져온다.") public void getReservation(){ Long restaurantId = 1004L; List<Reservation> reservations = reservationService.getReservations(restaurantId); verify(reservationRepository).findAllByRestaurantId(restaurantId); }} public class JwtAuthenticationFilter extends BasicAuthenticationFilter { private final JwtUtil jwtUtil; public JwtAuthenticationFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil) { super(authenticationManager); this.jwtUtil = jwtUtil; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { Authentication authentication = getAuthentication(request); if(authentication != null){ SecurityContext context = SecurityContextHolder.getContext(); context.setAuthentication(authentication); } chain.doFilter(request, response); } private Authentication getAuthentication(HttpServletRequest request){ // Header에서 Data를 얻어야 한다. String token = request.getHeader("Authorization"); if(token == null){ return null; } Claims claims = jwtUtil.getClaims(token.substring("Bearer ".length())); Authentication authentication = new UsernamePasswordAuthenticationToken(claims, null); return authentication; }} @Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Value("${jwt.secret}") private String secret; @Override protected void configure(HttpSecurity http) throws Exception { Filter filter = new JwtAuthenticationFilter(authenticationManager(), jwtUtil()); http .cors().disable() .csrf().disable() .formLogin().disable() .headers().frameOptions().disable(); http .addFilter(filter) .sessionManagement() // Session을 사용하지 않음 .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Bean public JwtUtil jwtUtil(){ return new JwtUtil(secret); }}

0

레스토랑 예약 사이트 만들기 13 - 인가

JWT로부터 데이터 가져오기public class JwtUtil { private Key key; public JwtUtil(String secret) { this.key = Keys.hmacShaKeyFor(secret.getBytes()); } public String createToken(Long userId, String name) { String token = Jwts.builder() .claim("userId", 1004L) .claim("name", name) .signWith(key, SignatureAlgorithm.HS256) .compact(); return token; } public Claims getClaims(String token){ Claims claims = Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); return claims; }} @Test@DisplayName("Claims를 가져온다.")public void getClaims(){ String token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEwMDQsIm5hbWUiOiJUZXN0ZXIifQ.I4DNdunio2m54tfUEaXHC_E-gvCQo6ZhHO15Ewkat6U"; Claims claims = jwtUtil.getClaims(token); assertThat(claims.get("userId", Long.class)).isEqualTo(1004L); assertThat(claims.get("name")).isEqualTo("Tester");} JWTFilter추가@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Value("${jwt.secret}") private String secret; @Override protected void configure(HttpSecurity http) throws Exception { Filter filter = new JwtAuthenticationFilter(authenticationManager(), jwtUtil()); http .cors().disable() .csrf().disable() .formLogin().disable() .headers().frameOptions().disable(); http .addFilter(filter) .sessionManagement() // Session을 사용하지 않음 .sessionCreationPolicy(SessionCreationPolicy.STATELESS); ; } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Bean public JwtUtil jwtUtil(){ return new JwtUtil(secret); }} JWT 인증 Filterpublic class JwtAuthenticationFilter extends BasicAuthenticationFilter { private JwtUtil jwtUtil; public JwtAuthenticationFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil) { super(authenticationManager); this.jwtUtil = jwtUtil; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { Authentication authentication = getAuthentication(request); if(authentication != null){ SecurityContext context = SecurityContextHolder.getContext(); context.setAuthentication(authentication); } chain.doFilter(request, response); } private Authentication getAuthentication(HttpServletRequest request){ // Header에서 Data를 얻어야 한다. String token = request.getHeader("Authorization"); if(token == null){ return null; } Claims claims = jwtUtil.getClaims(token.substring("Bearer ".length())); Authentication authentication = new UsernamePasswordAuthenticationToken(claims, null); return authentication; }} 요청시 Token값을 가지고 있는지 확인@RestController@RequiredArgsConstructorpublic class ReviewController { private final ReviewService reviewService; @PostMapping("/restaurants/{restaurantId}/reviews") public ResponseEntity<?> create( Authentication authentication, @PathVariable Long restaurantId, @Valid @RequestBody Review resource ) throws URISyntaxException { Claims claims = (Claims) authentication.getPrincipal(); String name = claims.get("name", String.class); Review review = reviewService.addReview(restaurantId, resource); String url = "/restaurants/" + restaurantId + "/reviews/" + review.getId(); return ResponseEntity.created(new URI (url)).body("{}"); }}

0

레스토랑 예약 사이트 만들기 12 - JWT

JWT를 이용해 AccesToken관리하기JwtUtil 클래스에서는 JWT를 생성하기 위한 createToken메서드가 존재한다. JWT에는 userId와 name을 넣을 것이고 HMAC-SHA256 해싱 알고리즘을 사용해 토큰의 유효성을 검사할 것이다. public class JwtUtil { private String secret; public JwtUtil(String secret) { this.secret = secret; } public String createToken(Long userId, String name) { Key key = Keys.hmacShaKeyFor(secret.getBytes()); String token = Jwts.builder() .claim("userId", 1004L) .claim("name", name) .signWith(key, SignatureAlgorithm.HS256) .compact(); return token; }} JWT가 올바르게 생성됐는지 확인하는 테스트 코드class JwtUtilTest { @Test public void createToken(){ String secret = "12345678901234567890123456789012"; JwtUtil jwtUtil = new JwtUtil(secret); String token = jwtUtil.createToken(1004L, ""); assertThat(token).contains("."); }} JwtUtil을 Bean으로 등록@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { // application.yml에 정의된 JWT Secret값을 가져온다. @Value("${jwt.secret}") private String secret; @Override protected void configure(HttpSecurity http) throws Exception { http .cors().disable() .csrf().disable() .formLogin().disable() .headers().frameOptions().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Bean public JwtUtil jwtUtil(){ return new JwtUtil(secret); }} 사용자 요청 결과로 JWT반환하는 로직을 구현/session 경로로 사용자 정보를 받으면 우선 사용자 유효성을 확인한 뒤, 등록된 사용자인 경우 사용자 정보를 JWT에 일부 담아 Response Body에 넣어 사용자에게 반환한다.

0

레스토랑 예약 사이트 만들기 11 - 인증

AccessToken을 이용한 인증@RestController@RequiredArgsConstructorpublic class SessionController { private final UserService userService; @PostMapping("/session") public ResponseEntity<SessionResponseDto> create(@RequestBody SessionRequestDto resource){ String email = resource.getEmail(); String password = resource.getPassword(); User user = userService.authenticate(email, password); String url = "/session"; String accessToken = user.getAccessToken(); SessionResponseDto sessionResponseDto = SessionResponseDto.builder() .accessToken(accessToken) .build(); return ResponseEntity.created(URI.create(url)).body(sessionResponseDto); }} @WebMvcTest(SessionController.class)class SessionControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test @DisplayName("AccessToken을 반환하는지 확인한다.") public void create() throws Exception { String email = "tester@example.com"; String password = "test"; User mockUser = User.builder().password("ACCESSTOKEN").build(); given(userService.authenticate(email, password)).willReturn(mockUser); ResultActions resultActions = mockMvc.perform(post("/session") .contentType(MediaType.APPLICATION_JSON) .content("{\"email\":\"tester@example.com\",\"password\":\"test\"}")); resultActions .andExpect(status().isCreated()) .andExpect(header().string("location", "/session")) // AccessToken을 사용하는지 확인한다. .andExpect(content().string("{\"accessToken\":\"ACCESSTOKE\"}")); verify(userService).authenticate(eq(email), eq(password)); } @Test @DisplayName("올바르지 않은 이메일을 이용한 요청을 시도") public void createWithNotExistedEmail() throws Exception { String email = "x@example.com"; String password = "test"; given(userService.authenticate(email, password)).willThrow(EmailNotExistedException.class); ResultActions resultActions = mockMvc.perform(post("/session") .contentType(MediaType.APPLICATION_JSON) .content("{\"email\":\"x@example.com\",\"password\":\"test\"}")); resultActions .andExpect(status().isBadRequest()); verify(userService).authenticate(eq(email), eq(password)); } @Test @DisplayName("올바르지 않은 패스워드를 이용한 요청을 시도") public void createWithInvalidAttributes() throws Exception { String email = "tester@example.com"; String password = "x"; given(userService.authenticate(email, password)).willThrow(PasswordWrongException.class); ResultActions resultActions = mockMvc.perform(post("/session") .contentType(MediaType.APPLICATION_JSON) .content("{\"email\":\"tester@example.com\",\"password\":\"x\"}")); resultActions .andExpect(status().isBadRequest()); verify(userService).authenticate(eq(email), eq(password)); }} public class EmailNotExistedException extends RuntimeException{ public EmailNotExistedException(){ super("Email is Not registered"); }} public class PasswordWrongException extends RuntimeException{ public PasswordWrongException(){ super("Password is Wrong"); }} @ControllerAdvicepublic class SessionErrorAdvice { @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(PasswordWrongException.class) public String handlePasswordWrong(){ return "{}"; } @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(EmailNotExistedException.class) public String handleEmailNotExisted(){ return "{}"; }} @Service@RequiredArgsConstructorpublic class UserService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; public User registerUser(String email, String name, String password) { // 회원이 이미 등록되어 있는지 Email을 통해 유효성 검사 Optional<User> optional = userRepository.findByEmail(email); // 회원이 이미 존재하는 경우 예외처리를 한다. if(optional.isPresent()){ throw new EmailExistedException(email); }// // 패스워드를 암호화해서 저장한다.// // 암호화 방식은 BCrypt방식을 이용해 암호화를 진행// BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String encodedPassword = passwordEncoder.encode(password); User user = User.builder() .email(email) .name(name) .password(encodedPassword) .level(1L) .build(); userRepository.save(user); return user; } public User authenticate(String email, String password) { User user = userRepository.findByEmail(email) .orElseThrow(() -> new EmailNotExistedException()); String encodedPassword = passwordEncoder.encode(password); if(!passwordEncoder.matches(password, user.getPassword())){ throw new PasswordWrongException(); } return user; }} @Test@DisplayName("올바른 파라미터를 이용해 사용자 유효성 검사를 한다.")public void authenticateWithValidAttributes(){ String email = "test@example.com"; String name = "Tester"; String password = "test"; User mockUser = User.builder() .Id(1004L) .email(email) .name(name) .password(password) .build(); given(userRepository.findByEmail(email)).willReturn(Optional.of(mockUser)); given(passwordEncoder.matches(any(), any())).willReturn(true); User user = userService.authenticate(email, password); assertThat(user.getEmail()).isEqualTo(email);}@Test@DisplayName("올바르지 않은 이메일을 이용해 사용자 유효성 검사를 한다.")public void authenticateNotValidEmail(){ String email = "x@example.com"; String password = "test"; given(userRepository.findByEmail(email)).willThrow(EmailNotExistedException.class); assertThatThrownBy(()->{ User user = userService.authenticate(email, password); }).isInstanceOf(EmailNotExistedException.class);}@Test@DisplayName("올바르지 않은 이메일을 이용해 사용자 유효성 검사를 한다.")public void authenticateNotValidPassword(){ String email = "test@example.com"; String name = "Tester"; String password = "x"; User mockUser = User.builder() .Id(1004L) .email(email) .name(name) .password(password) .build(); given(userRepository.findByEmail(email)).willReturn(Optional.of(mockUser)); given(passwordEncoder.matches(password, mockUser.getPassword())).willReturn(false); assertThatThrownBy(()->{ User user = userService.authenticate(email, password); }).isInstanceOf(PasswordWrongException.class);} @Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .cors().disable() .csrf().disable() .formLogin().disable() .headers().frameOptions().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }}

0

레스토랑 예약 사이트 만들기 10 - 회원 가입

Security 설정하기@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .cors().disable() .csrf().disable() .formLogin().disable() .headers().frameOptions().disable(); }} @Service@RequiredArgsConstructorpublic class UserService { private final UserRepository userRepository; public User registerUser(String email, String name, String password) { User user = User.builder() .email(email) .name(name) .password(encodedPassword) .level(1L) .build(); userRepository.save(user); return user; }} 패스워드에 암호화 하기@Service@RequiredArgsConstructorpublic class UserService { private final UserRepository userRepository; public User registerUser(String email, String name, String password) { // 패스워드를 암호화해서 저장한다. BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String encodedPassword = passwordEncoder.encode(password); User user = User.builder() .email(email) .name(name) .password(encodedPassword) .level(1L) .build(); userRepository.save(user); return user; }} class UserServiceTest { @Mock private UserRepository userRepository; private UserService userService; @BeforeEach public void setUp(){ MockitoAnnotations.openMocks(this); userService = new UserService(userRepository); } @Test @DisplayName("사용자를 등록한다.") public void registerUser(){ String email = "test@example.com"; String name = "Tester"; String password = "test"; User user = userService.registerUser(email, name, password); assertThat(user.getEmail()).isEqualTo(email); assertThat(user.getName()).isEqualTo(name); assertThat(user.getPassword()).isEqualTo(password); verify(userRepository).save(any()); }} @RestController@RequiredArgsConstructorpublic class UserController { private final UserService userService; @PostMapping("/users") public ResponseEntity<?> create(@RequestBody User resource){ String email = resource.getEmail(); String name = resource.getName(); String password = resource.getPassword(); User user = userService.registerUser(email, name, password); String url = "/users/" + user.getId(); return ResponseEntity.created(URI.create(url)).body("{}"); }} @WebMvcTest(UserController.class)class UserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test @DisplayName("사용자를 생성한다.") public void create() throws Exception { String email = "tester@example.com"; String name = "Tester"; String password = "test"; User mockUser = User.builder() .Id(1004L) .email(email) .password(password) .name(name) .build(); given(userService.registerUser(email, name, password)) .willReturn(mockUser); ResultActions resultActions = mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content("{\"email\" : \"tester@example.com\", \"name\" : \"Tester\", \"password\" : \"test\"}")); resultActions .andExpect(status().isCreated()) .andExpect(header().string("location", "/users/1004")); verify(userService).registerUser(any(), any(), any()); }} 존재하는 회원에 대한 예외처리

0

레스토랑 예약 사이트 만들기 9 - 사용자 관리

@Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long Id; @NotEmpty private String email; @NotEmpty private String name; @NotNull private Long level; public boolean isAdmin() { return level > 2L; } public void deactivate(){ level = 0L; } public boolean isActive() { return level > 0L; }} @Repositorypublic interface UserRepository extends JpaRepository<User, Long> {} @Service@RequiredArgsConstructorpublic class UserService { private final UserRepository userRepository; public List<User> getUsers() { return userRepository.findAll(); } public User addUser(String email, String name) { User user = User.builder() .email(email) .name(name) .level(1L) .build(); userRepository.save(user); return user; } public User updateUser(Long id, String email, String name, Long level ) { User user = userRepository.findById(id).orElse(null); user.setEmail(email); user.setName(name); user.setLevel(level); return user; } public User deactivateUser(Long userId) { User user = userRepository.findById(userId).orElse(null); user.deactivate(); return user; }} class UserServiceTest { @Mock private UserRepository userRepository; private UserService userService; @BeforeEach private void setUp() { MockitoAnnotations.openMocks(this); userService = new UserService(userRepository); } @Test @DisplayName("유저목록을 가져온다.") public void getUsers() { List<User> mockUsers = new ArrayList<>(); mockUsers.add(User.builder() .name("tester") .email("test@example.com") .level(3L) .build()); given(userRepository.findAll()).willReturn(mockUsers); List<User> users = userService.getUsers(); User user = users.get(0); assertThat(user.getName()).isEqualTo("tester"); assertThat(user.getEmail()).isEqualTo("test@example.com"); } @Test @DisplayName("유저를 추가한다.") public void addUser(){ String email = "test@example.com"; String name = "tester"; User mockUser = User.builder() .name(name) .email(email) .build(); given(userRepository.save(any())).willReturn(mockUser); User user = userService.addUser(email, name); assertThat(user.getName()).isEqualTo(name); assertThat(user.getEmail()).isEqualTo(email); } @Test @DisplayName("유저를 업데이트 한다.") public void updateUser(){ Long id = 1004L; Long level = 3L; String email = "test@example.com"; String name = "Superman"; User mockUser = User.builder() .Id(id) .name("Administrator") .level(1L) .email(email) .build(); given(userRepository.findById(id)).willReturn(Optional.of(mockUser)); User user = userService.updateUser(id, email, name, level); verify(userRepository).findById(id); assertThat(user.getName()).isEqualTo("Superman"); assertThat(user.isAdmin()).isEqualTo(true); } @Test @DisplayName("유저를 삭제한다.") public void deactiveUser(){ Long id = 1004L; Long level = 2L; String email = "test@example.com"; String name = "Superman"; User mockUser = User.builder() .Id(id) .level(level) .email(email) .name(name) .build(); given(userRepository.findById(id)).willReturn(Optional.of(mockUser)); User user = userService.deactivateUser(1004L); verify(userRepository).findById(1004L); assertThat(user.isAdmin()).isEqualTo(false); assertThat(user.isActive()).isEqualTo(false); }} @RestController@RequiredArgsConstructorpublic class UserController { // 1. User list // 2. User create -> 회원가입 // 3. User update // 4. User delete -> level: 0 => 아무것도 못 함. // (1: customer 2: restaurant owner 3: admin) private final UserService userService; @GetMapping("/users") public List<User> list(){ return userService.getUsers(); } @PostMapping("/users") public ResponseEntity<?> create(@RequestBody User resource) throws URISyntaxException { User user = userService.addUser(resource.getEmail(), resource.getName()); String url = "/users" + user.getId(); return ResponseEntity.created(URI.create(url)).body("{}"); } @PatchMapping("/users/{userId}") public void udpate(@PathVariable("userId") Long id, @RequestBody User user){ userService.updateUser(id, user.getEmail(), user.getName(), user.getLevel()); } @DeleteMapping("/users/{userId}") public String deactivate(@PathVariable("userId")Long userId){ userService.deactivateUser(userId); return "{}"; }} @WebMvcTest(UserController.class)class UserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test @DisplayName("유저목록을_가져온다") public void list() throws Exception { List<User> users = new ArrayList<>(); users.add(User.builder() .email("tester@example.com") .name("tester") .level(1L) .build()); given(userService.getUsers()).willReturn(users); mockMvc.perform(get("/users")) .andExpect(status().isOk()) .andExpect(content().string(containsString("tester"))); } @Test @DisplayName("유저를 추가한다.") public void create() throws Exception { String email = "admin@example.com"; String name = "Administrator"; User user = User.builder() .email(email) .name(name) .build(); given(userService.addUser(email, name)).willReturn(user); ResultActions resultActions = mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content("{\"email\" : \"admin@example.com\", \"name\" : \"Administrator\"}")); verify(userService).addUser(email, name) ; resultActions .andExpect(status().isCreated()); } @Test @DisplayName("유저상태를 업데이트 한다") public void update() throws Exception { Long id = 1004L; String email = "admin@example.com"; String name = "Administrator"; Long level = 3L; User user = User.builder() .email(email) .name(name) .level(level) .build(); given(userService.updateUser(id, email, name, level)).willReturn(user); ResultActions resultActions = mockMvc.perform(patch("/users/1004") .contentType(MediaType.APPLICATION_JSON) .content("{\"level\": 3" + ",\"email\" : \"admin@example.com\"" + ", \"name\" : \"Administrator\"}")); verify(userService).updateUser(eq(id), eq(email), eq(name), eq(level)); resultActions .andExpect(status().isOk()); } @Test @DisplayName("유저를 삭제한다.") public void deactivate() throws Exception { mockMvc.perform(delete("/users/1004")) .andExpect(status().isOk()); verify(userService).deactivateUser(1004L); }}

0

레스토랑 예약 사이트 만들기 8 - 가게목록 필터링

@Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class Region { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name;} @Repositorypublic interface RegionRepository extends JpaRepository<Region,Long> {} @Service@RequiredArgsConstructorpublic class RegionService { private final RegionRepository regionRepository; public List<Region> getRegions() { return regionRepository.findAll(); }} @Service@RequiredArgsConstructorpublic class RegionService { private final RegionRepository regionRepository; public List<Region> getRegions() { return regionRepository.findAll(); }} class RegionServiceTest { private RegionService regionService; @Mock private RegionRepository regionRepository; @BeforeEach public void setUp(){ MockitoAnnotations.openMocks(this ); regionService = new RegionService(regionRepository); } @Test public void 지역정보들을_가져온다() { List<Region> mockRegions = new ArrayList<>(); mockRegions.add(Region.builder() .name("Seoul") .build()); given(regionRepository.findAll()).willReturn(mockRegions); List<Region> regions = regionService.getRegions(); Region region = regions.get(0); assertThat(region.getName()).isEqualTo("Seoul"); }} @RestController@RequiredArgsConstructorpublic class RegionController { private final RegionService regionService; @GetMapping("/regions") public List<Region> list(){ List<Region> regions = regionService.getRegions(); return regions; }} @WebMvcTest(RegionController.class)class RegionControllerTest { @Autowired private MockMvc mockMvc; @MockBean private RegionService regionService; @Test public void 지역목록들을_가져온다() throws Exception { List<Region> regions = new ArrayList<>(); regions.add(Region.builder().name("Seoul").build()); given(regionService.getRegions()).willReturn(regions); mockMvc.perform(get("/regions")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Seoul"))); }} 카테고리 만들기@Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; public String name;}

0

레스토랑 예약 사이트 만들기 7 - 멀티모듈

dependencies { implementation project(':eatgo-common') implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test'} jar { enabled = true}bootJar { enabled = false} @Testpublic void 레스토랑에_해당되는_메뉴들을_반환한다() { List<MenuItem> mockMenuItems = new ArrayList<>(); mockMenuItems.add(MenuItem.builder() .name("Kimchi") .build()); given(menuItemRepository.findAllByRestaurantId(1004L)).willReturn(mockMenuItems); List<MenuItem> menuItems = menuItemService.getMenuItems(1004L); MenuItem menuItem = menuItems.get(0); assertThat(menuItem.getName()).isEqualTo("Kimchi");} public List<MenuItem> getMenuItems(Long restaurantId) { return menuItemRepository.findAllByRestaurantId(restaurantId);} 리뷰 정보 가져오기@GetMapping("/reviews")public List<Review> list(){ List<Review> reviews = reivewService.getReviews(); return reviews;} @Testpublic void 레스토랑에_해당되는_리뷰들을_가져온다() throws Exception { List<Review> mockReviews = new ArrayList<>(); mockReviews.add(Review.builder() .description("Cool!") .build()); given(reviewService.getReviews()).willReturn(mockReviews); mockMvc.perform(get("/reviews")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Cool!")));} public List<Review> getReviews() { return reviewRepository.findAll();} @Testpublic void 리뷰들을_가져온다(){ List<Review> mockReviews = new ArrayList<>(); mockReviews.add(Review.builder() .description("Cool!") .build()); given(reviewRepository.findAll()).willReturn(mockReviews); List<Review> reviews = reviewService.getReviews(); Review review = reviews.get(0); assertThat(review.getDescription()).isEqualTo("Cool!");}

0

레스토랑 예약 사이트 만들기 6 - 리뷰 기능

새로운 리뷰 생성 오청을 처리하기 위한 control@RestController@RequiredArgsConstructorpublic class ReviewController { private final ReviewService reivewService; @PostMapping("/restaurants/{restaurantId}/reviews") public ResponseEntity<?> create( @PathVariable Long restaurantId, @Valid @RequestBody Review resource ) throws URISyntaxException { Review review = reivewService.addReview(restaurantId, resource); String url = "/restaurants/" + restaurantId + "/reviews/" + review.getId(); return ResponseEntity.created(new URI (url)).body("{}"); }} @WebMvcTest(ReviewController.class)class ReviewControllerTest { @Autowired private MockMvc mockMvc; @MockBean private ReviewService reviewService; @Test public void 리뷰를_생성한다() throws Exception { given(reviewService.addReview(eq(1L), any())).willReturn( Review.builder() .id(1004L) .name("JOKER") .score(3) .description("Mat-it-da") .build()); mockMvc.perform(post("/restaurants/1/reviews") .contentType(MediaType.APPLICATION_JSON) .content("{\"name\":\"JOKER\", \"score\":3,\"description\" : \"Mat-it-da\"}")) .andExpect(status().isCreated()) .andExpect(header().string("location", "/restaurants/1/reviews/1004")); verify(reviewService).addReview(eq(1L), any()); }} Review 도메인 객체를 생성@Entity@Builder@NoArgsConstructor@AllArgsConstructor@Getter@Setterpublic class Review { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull private Long restaurantId; @NotEmpty private String name; @NotNull private Integer score; @NotEmpty private String description;} Review를 저장하기 위한 Repository 생성@Repositorypublic interface ReviewRepository extends JpaRepository<Review, Long> { List<Review> findAllByRestaurantId(Long restaurantId);} Review Service 클래스를 생성한다.@Service@RequiredArgsConstructorpublic class ReviewService { private final ReviewRepository reviewRepository; public Review addReview(Long restaurantId, Review review) { review.setRestaurantId(restaurantId); reviewRepository.save(review); return review; }}