Archive: 2021

0

레스토랑 예약 사이트 만들기 5 - 메뉴 관리

메뉴를 추가하는 요청을 처리하기 위한 control@RestController@RequiredArgsConstructorpublic class MenuItemController { private final MenuItemService menuItemService; @PatchMapping("/restaurants/{restaurantId}/menuitems") public String buikUpdate(){ List<MenuItem> menuItems = new ArrayList<>(); menuItemService.bulkUpdate(menuItems); return ""; }} @WebMvcTest(MenuItemController.class)class MenuItemControllerTest { @Autowired private MockMvc mockMvc; @MockBean private MenuItemService menuItemService; @Test public void bulkUpdate() throws Exception { ResultActions resultActions = mockMvc.perform(patch("/restaurants/1/menuitems") .contentType(MediaType.APPLICATION_JSON) .content("[]")); resultActions .andExpect(status().isOk()); verify(menuItemService).bulkUpdate(any()); }} @Service@RequiredArgsConstructorpublic class MenuItemService { private final MenuItemRepository menuItemRepository; public void bulkUpdate(Long restaurantId, List<MenuItem> menuItems) { for(MenuItem menuItem : menuItems){ menuItem.setRestaurantId(restaurantId); menuItemRepository.save(menuItem); } }} class MenuItemServiceTest { private MenuItemService menuItemService; @Mock private MenuItemRepository menuItemRepository; @BeforeEach public void setUp(){ MockitoAnnotations.initMocks(this); menuItemService = new MenuItemService(menuItemRepository); } @Test public void bulkUpdate() { List<MenuItem> menuItems = new ArrayList<>(); menuItems.add(MenuItem.builder() .name("Kimchi") .build()); menuItems.add(MenuItem.builder() .name("Gukbob") .build()); menuItemService.bulkUpdate(1L, menuItems); verify(menuItemRepository, times(2)).save(any());; }} 메뉴 삭제 요청@Builder@Entity@Setter@Getter@NoArgsConstructor@AllArgsConstructorpublic class MenuItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long restaurantId; private String name; @Transient private boolean destroy; public MenuItem(String name){ this.name = name; }} @Service@RequiredArgsConstructorpublic class MenuItemService { private final MenuItemRepository menuItemRepository; public void bulkUpdate(Long restaurantId, List<MenuItem> menuItems) { for(MenuItem menuItem : menuItems){ updateOrDeleteMenuItems(restaurantId, menuItem); } } private void updateOrDeleteMenuItems(Long restaurantId, MenuItem menuItem) { if(menuItem.isDestroy()){ menuItemRepository.deleteById(menuItem.getId()); }else { menuItem.setRestaurantId(restaurantId); menuItemRepository.save(menuItem); } }} @Testpublic void 메뉴를_삭제한다() { List<MenuItem> menuItems = new ArrayList<>(); menuItems.add(MenuItem.builder() .name("Kimchi") .build()); menuItems.add(MenuItem.builder() .name("Gukbob") .build()); menuItems.add(MenuItem.builder() .id(1004L) .destroy(true) .build()); menuItemService.bulkUpdate(1L, menuItems); verify(menuItemRepository, times(2)).save(any()); verify(menuItemRepository, times(1)).deleteById(eq(1004L));}

0

레스토랑 예약 사이트 만들기 4 - 예외 처리

없는 페이지 요청에 대한 예외처리@Testpublic void 없는_페이지에대한_예외처리를_한다() throws Exception{ given(restaurantService.getRestaurant(404L)).willThrow(new RestaurantNotFoundException(404L)); ResultActions resultActions = mockMvc.perform(get("/restaurants/404")); resultActions .andExpect(status().isNotFound()) .andExpect(content().string("{}"));} public class RestaurantNotFoundException extends RuntimeException{ public RestaurantNotFoundException(Long id) { super("Could not find Restaurant" + id ); }} @ControllerAdvicepublic class RestaurantErrorAdvice { @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(RestaurantNotFoundException.class) public String handleNotFound(){ return "{}"; }} Service 계층에서의 예외처리@Testpublic void 없는_레스토랑을_가져온다() { assertThatThrownBy(() -> { Restaurant restaurant = restaurantService.getRestaurant(404L); }).isInstanceOf(RestaurantNotFoundException.class);// Restaurant restaurant = restaurantService.getRestaurant(404L);} public Restaurant getRestaurant(Long id) { Optional<Restaurant> optional = restaurantRepository.findById(id); if (optional.isPresent()) { List<MenuItem> menuItems = menuItemRepository.findAllByRestaurantId(id); Restaurant restaurant = new Restaurant(); restaurant.setMenuItems(menuItems); return restaurant; }else{ throw new RestaurantNotFoundException(id); }}

0

레스토랑 예약 사이트 만들기 3

<!DOCTYPE html><html lang="ko"><head> <meta charset="UTF-8"> <title>Title</title></head><body><div id="app">Hello, world!</div><script src="./src/index.js"></script></body></html> (async () => { const url = "http://localhost:8080/restaurants"; const response = await fetch(url); const restaurants = await response.json(); console.log(restaurants); const element = document.getElementById('app'); element.innerHTML = JSON.stringify(restaurants);})(); (async () => { const url = "http://localhost:8080/restaurants"; const response = await fetch(url); const restaurants = await response.json(); console.log(restaurants); const element = document.getElementById('app'); element.innerHTML = ` ${restaurants[0].id} ${restaurants[0].name} `})(); (async () => { const url = "http://localhost:8080/restaurants"; const response = await fetch(url); const restaurants = await response.json(); console.log(restaurants); const element = document.getElementById('app'); element.innerHTML = ` ${restaurants.map(restaurant => ` <p> ${restaurant.id} ${restaurant.name} ${restaurant.address} </p> `).join('')} `;})();

0

레스토랑 예약 사이트 만들기 2 - 메뉴 정보 추가(관리자)

레스토랑에 메뉴정보를 담기@Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class Restaurant { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull private Long categoryId; @NotEmpty private String name; @NotEmpty private String address; @Transient @JsonInclude(JsonInclude.Include.NON_NULL) private List<MenuItem> menuItems; public void addMenuItem(MenuItem menuItem){ menuItems.add(menuItem); } public void setMenuItems(List<MenuItem> menuItems){ this.menuItems = new ArrayList<>(menuItems); } public String getInformation(){ return name + " in " + address; }} 메뉴에 대한 정보를 담고있는 MenuItem 클래스@Builder@Entity@Setter@Getter@NoArgsConstructor@AllArgsConstructorpublic class MenuItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long restaurantId; private String name; @Transient @JsonInclude(JsonInclude.Include.NON_DEFAULT) private boolean destroy; public MenuItem(String name){ this.name = name; }} 레스토랑에서 메뉴정보 가져오기public interface MenuItemRepository extends JpaRepository<MenuItem, Long> { List<MenuItem> findAllByRestaurantId(Long restaurantId);} 레스토랑에 메뉴등록 요청 보내기추가하고자 하는 데이터는 Http Body에 넣어서 보낸다.

0

레스토랑 예약 사이트 1 - 레스토랑 관리(사용자) 레스토랑 정보 가져오기

사용자 페이지사용자의 경우 레스토랑을 관리하지 않으므로 레스토랑 정보를 추가하거나 수정할필요는 없고 조회하는 기능만 있으면 된다. 모든 Restaurant정보 가져오기 특정 Restaurant정보 가져오기 Request Parameter를 통한 레스토랑 조회 control요청시 RequestParameter를 통해 원하는 지역, 카테고리를 통해 해당 조건을 만족하는 레스토랑 정보를 모두 가져올 수 있도록 한다. 특정 Restaurant 정보를 가져오는 함수들은 관리자에서 만들었던 내용과 같으므로 생각한다. @CrossOrigin@RestController@RequiredArgsConstructorpublic class RestaurantController { private final RestaurantService restaurantService; @GetMapping("/restaurants") public List<Restaurant> list(@RequestParam("region") String region, @RequestParam("category") Long category) { List<Restaurant> restaurants = restaurantService.getRestaurants(region, category); return restaurants; } @GetMapping("/restaurants/{id}") public Restaurant detail(@PathVariable Long id) throws Exception { Restaurant restaurant = restaurantService.getRestaurant(id); return restaurant; }} Request Parameter를 통한 레스토랑 조회 테스트 코드 작성@Testpublic void RequestParameter를_이용한_list를_확인한다() throws Exception { List<Restaurant> restaurants = new ArrayList<>(); restaurants.add(Restaurant.builder() .id(1004L) .categoryId(1L) .name("JOKER House") .address("Seoul") .build()); given(restaurantService.getRestaurants("Seoul", 1L)).willReturn(restaurants); ResultActions resultActions = mockMvc.perform(get("/restaurants?region=Seoul&category=1")); resultActions .andExpect(status().isOk()) .andExpect(content().string(containsString("\"id\":1004"))) .andExpect(content().string(containsString("\"name\":\"JOKER House\""))) .andDo(print());}

0

레스토랑 예약 사이트 1 - 레스토랑 관리(관리자) 레스토랑 정보 업데이트

4. 레스토랑 정보 업데이트레스토랑 업데이트 하기 위한 control 추가레스토랑 정보를 업데이트 하기 위해서는 업데이트 하고자 하는 레스토랑을 가지고 와야 한다. /restaurants경로뒤에 레스토랑 id를 붙여 요청이 들어오면 id를 이용해 레스토랑을 찾고 request body에 들어있는 정보로 레스토랑을 업데이트 한다. 업데이트 요청을 처리하기 위해 Http 메소드 중에서 patch메소드를 이용할 것이다. @PatchMapping("/restaurants/{id}")public String update(@PathVariable("id") Long id, @RequestBody Restaurant restaurant) throws Exception { restaurantService.updateRestaurant(id, restaurant.getName(), restaurant.getAddress()); return "{}";} 업데이트 요청에 대한 테스트 코드 작성@Testpublic void 레스토랑정보_업데이트() throws Exception { String JOKER = "JOKER Bar"; String Busan = "Busan"; Restaurant restaurant = Restaurant.builder() .categoryId(1L) .name(JOKER) .address(Busan) .build(); String content = objectMapper.writeValueAsString(restaurant); ResultActions resultActions = mockMvc.perform(patch("/restaurants/1004") .contentType(MediaType.APPLICATION_JSON) .content(content)); resultActions .andExpect(status().isOk()) .andDo(print()); verify(restaurantService).updateRestaurant(1004L, JOKER, Busan);} 레스토랑 업데이트를 하기 위한 Service 메소드먼저 id를 갖고 저장돼 있는 해당 레스토랑을 가져온 후 전달 받은 name값과 address값으로 업데이트 한다. 만약 해당 레스토랑이 없을 경우 RestaurantNotFoundException예외를 일으키도록 한다.

0

레스토랑 예약 사이트 1 - 레스토랑 관리(관리자) 레스토랑 생성

3. 레스토랑 추가하기레스토랑 생성 요청을 처리하기 위한 control 추가Http 메소드들 중에서 post메소드를 사용해 새로운 레스토랑을 추가하는 요청을 처리할 것이고, /restaurnt경로로 요청이 들어올 경우 request body에 들어가 있는 데이터를 가져와 새로운 레스토랑을 생성한다. @PostMapping("/restaurants")public ResponseEntity<?> create(@RequestBody Restaurant resource) throws URISyntaxException { String name = resource.getName(); String address = resource.getAddress(); Restaurant restaurant = Restaurant.builder() .name(name) .address(address) .build(); restaurantService.addRestaurant(restaurant); URI location = new URI("/restaurants/" + restaurant.getId()); return ResponseEntity.created(location).body("{}");} 요청에 대한 레스토랑 생성 테스트 코드 작성POJO를 JSON형태로 변환하기 위해 Jackson라이브러리의 ObjectMapper를 사용할 것이다.ObjectMapper를 통해 Restaurant객체를 JSON String 형태로 변환해 request body에 넣어 /restaurants경로로 post요청을 한다. @Autowiredprivate ObjectMapper objectMapper;@Testpublic void 새로운_레스토랑_저장하기() throws Exception { String BobZip = "BobZip"; String Seoul = "Seoul"; Restaurant restaurant = Restaurant.builder() .categoryId(1L) .name(BobZip) .address(Seoul) .build(); // POJO를 JSON형태로 변환해준다. String content = objectMapper.writeValueAsString(restaurant); ResultActions resultActions = mockMvc.perform(post("/restaurants") .content(content) .contentType(MediaType.APPLICATION_JSON)); resultActions .andExpect(status().isCreated()) .andDo(print());} 새로운 레스토랑을 생성하는 요청을 한 후 레스토랑의 정보를 가져오는 요청을 해 해당 정보가 제대로 생성 됐는지 확인한다. @Testpublic void 새로운_레스토랑_저장_및_조회하기() throws Exception { String BobZip = "BobZip"; String Seoul = "Seoul"; Restaurant restaurant = Restaurant.builder() .categoryId(1L) .name(BobZip) .address(Seoul) .build(); String content = objectMapper.writeValueAsString(restaurant); ResultActions postResultActions = mockMvc.perform(post("/restaurants") .content(content) .contentType(MediaType.APPLICATION_JSON)); postResultActions .andExpect(status().isCreated()) .andDo(print()); List<Restaurant> restaurants = new ArrayList<>(); restaurants.add(restaurant); given(restaurantService.getRestaurants()).willReturn(restaurants); ResultActions getResultActions = mockMvc.perform(get("/restaurants")); getResultActions .andExpect(status().isOk()) .andExpect(jsonPath("$[0].name").value(BobZip)) .andExpect(jsonPath("$[0].address").value(Seoul)) .andDo(print());}

0

레스토랑 예약 사이트 1 - 레스토랑 관리(관리자) 특정 레스토랑 가져오기

2. 특정 레스토랑에 대한 정보 가져오기특정가게에 대한 상세정보 요청을 처리하기 위한 control 추가특정 레스토랑의 정보를 가져오고 싶을 경우 restaurant의 Id값을 이용할 수 있다. /restaurant경로에 사용자가 원하는 restaurantId 를 더해 해당 레스토랑에 대한 정보를 반환하도록 한다. @GetMapping("/restaurants/{id}")public Restaurant detail(@PathVariable Long id) throws Exception { Restaurant restaurant = restaurantService.getRestaurant(id); return restaurant;} 테스트 코드 작성특정 id값으로 갖는 restaurant에 대한 정보를 가져오는 테스트를 구현한다. 요청이 정상적으로 진행된 경우에는 Status으로 200과 함께 해당 레스토랑에 대한 정보를 받을 수 있다. @Testpublic void 특정_가게_상세정보를_가져온다() throws Exception { Restaurant restaurant = Restaurant.builder() .id(1004L) .categoryId(1L) .name("JOKER House") .address("Seoul") .build(); given(restaurantService.getRestaurant(1004L)).willReturn(restaurant); ResultActions resultActions = mockMvc.perform(get("/restaurants/1004")); resultActions .andExpect(status().isOk()) // 레스토랑 정보가 들어있는지 확인한다. .andExpect(content().string(containsString("\"id\":1004"))) .andExpect(content().string(containsString("\"name\":\"JOKER House\"")));} 특정 레스토랑을 가져오는 Service로직RestaurantRepository 객체를 이용해 DB로부터 id값이 일치하는 레스토랑 정보를 가져온다. 만약 해당되는 Restaurant정보가 없다면 RestaurantNotFoundException을 발생시킨다.

0

레스토랑 예약 사이트 1 - 레스토랑 관리(관리자) 모든 레스토랑 가져오기

패스트 캠퍼스에서 레스토량 예약 사이트 만드는 Toy project를 진행 했다. 해당 프로젝트를 진행하면서 배울 수 있었던 것은 TDD, 스프링부트를 이용한 Rest-Api작성 Multi-Module을 이용한 프로젝트 진행을 배울 수 있었다. 강의 내용들을 블로그 포스팅을 통해 다시 되집어 보려고 한다. 관리자 페이지 모든 Restaurant정보 가져오기 특정 Restaurant정보 가져오기 Restaurant 추가하기 Restaurant정보 수정하기 1. 모든 레스토랑에 대한 정보를 가져오기Restaurant Controller 생성레스토랑을 예약하기 위해서 예약할 수 있는 레스토랑 목록을 알아야 한다. /restaurant로 접근하면 모든 레스토랑의 정보를 가져올 수 있도록 한다. RestaurantRepository 로부터 바로 데이터를 가져와 사용자에게 넘겨줘도 되지만, Service 계층을 넣어 데이터를 처리하는 로직과 사용자에게 View를 보여주는 control로직을 분리하도록 한다. @RestController@RequiredArgsConstructorpublic class RestaurantController { private final RestaurantService restaurantService; @GetMapping("/restaurants") public List<Restaurant> list() { List<Restaurant> restaurants = restaurantService.getRestaurants(); return restaurants; }}

0

Spring Rest API - ExceptionHandling

목차 Spring Rest API - Spring Boot Swagger 사용하기 Spring Rest API - ExceptionHandling Spring Rest API - HTTP Status Code 다루기 Spring Rest API - 도메인 및 서비스 로직 작성하기 Spring Rest API - Rest API 시작하기 Controller 작성 Spring Boot Rest API - ExceptionHandling존재하지 않는 id값에 대한 예외처리 추가저장되지 않은 User를 조회할 경우 UserNotFoundException 예외가 발생하도록 예외처리한다. UserController.java @GetMapping("/users/{id}")public User retrieveUser(@PathVariable int id){ User user = service.findOne(id); if(user == null){ throw new UserNotFoundException(String.format("ID[%s] not found", id )); } return user;} 예외처리하는 Exception 클래스 생성ResponseStatus 를 이용해 HttpStatus.NOT_FOUND 옵션을 설정할 경우 UserNotFoundException 예외가 발생했을때 Http Status Code 404(Not Found) 가 반환된다.

0

Spring Rest API - HTTP Status Code 다루기

목차 Spring Rest API - Spring Boot Swagger 사용하기 Spring Rest API - ExceptionHandling Spring Rest API - HTTP Status Code 다루기 Spring Rest API - 도메인 및 서비스 로직 작성하기 Spring Rest API - Rest API 시작하기 Controller 작성 Spring Boot Rest API - HTTP Status Code 다루기201(Created) 코드 반환하기 사용자가 요청으로 새로운 User가 생성됨을 확인하기 위해 201(Created) 코드를 반환한다. @PostMapping("/users")public ResponseEntity<User> createUser(@RequestBody @Valid User user){ User savedUser = service.save(user); URI location = ServletUriComponentsBuilder.fromCurrentRequest() .path("/{id}") .buildAndExpand(savedUser.getId()) .toUri(); return ResponseEntity.created(location).build();} 201(Created) 코드를 확인하기 위한 Test Code 작성@Testpublic void 유저를_등록하고_상태코드_201을_확인한다() throws Exception { User user = new User(); String name = "dongwoo"; Date date = new Date(); user.setName(name); user.setJoinDate(date); String content = objectMapper.writeValueAsString(user); ResultActions resultActions = mockMvc.perform(post("/users") .content(content) .contentType(MediaType.APPLICATION_JSON)); resultActions .andExpect(status().isCreated()) .andDo(print());}

0

레스토랑 예약 사이트 1 - 레스토랑 관리 Domain 생성

Restaurant Entity 클래스Restaurant 클래스에는 id , name, address를 저장한다. id : 레스토랑을 구분하기 위한 Id값 name : 레스토랑의 이름 address : 레스토랑의 위치 @Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class Restaurant { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotEmpty private String name; @NotEmpty private String address;} Restaurant 클래스에 대한 테스트 코드 작성@Testpublic void creation(){ String name = "OutBack"; String address = "Seoul"; long id = 1004L; Restaurant restaurant = new Restaurant(id, name, address); assertThat(restaurant).isNotNull(); assertThat(restaurant.getId()).isEqualTo(id); assertThat(restaurant.getName()).isEqualTo(name); assertThat(restaurant.getAddress()).isEqualTo(address);} Restaurant Repository 생성Restaurant에 대한 정보를 가져오고 저장하고 수정하기 위한 Repository를 생성한다. Repository는 DB에 접근해 CRUD를 실행할 수 있다. @Repositorypublic interface RestaurantRepository extends JpaRepository<Restaurant, Long> {}

0

Spring Rest API - 도메인 및 서비스 로직 작성하기

목차 Spring Rest API - Spring Boot Swagger 사용하기 Spring Rest API - ExceptionHandling Spring Rest API - HTTP Status Code 다루기 Spring Rest API - 도메인 및 서비스 로직 작성하기 Spring Rest API - Rest API 시작하기 Controller 작성 Spring Boot Rest API - 도메인 및 서비스 로직 작성하기User 도메인 클래스 생성@Data@AllArgsConstructor@NoArgsConstructorpublic class User { private Integer id; private String name; private Date joinDate;} 서비스 클래스 생성@Servicepublic class UserDaoService { // 관계형 데이터베이스를 사용하지 않고 Memory 데이터를 사용 private static List<User> users = new ArrayList<>(); private static int usersCount = 3; static{ users.add(new User(1, "Kenneth", new Date())); users.add(new User(2, "Alice", new Date())); users.add(new User(3, "Elena", new Date())); } // 전체 사용자 조회 public List<User> findAll(){ return users; } // 개별 사용자 조회 public User save(User user){ if(user.getId() == null){ user.setId(++usersCount); } users.add(user); return user; } // id값을 이용한 사용자 조회 public User findOne(int id){ for (User user : users){ if(user.getId() == id){ return user; } } return null; }} 사용자 요청 처리 Controller 추가@RestController@RequiredArgsConstructorpublic class UserController { private final UserDaoService service; @GetMapping("/users") public List<User> retrieveAllUsers(){ return service.findAll(); } // path variable을 이용한 요청을 처리 @GetMapping("/users/{id}") public User retrieveUser(@PathVariable int id){ User user = service.findOne(id); return user; }}

0

Spring Rest API - Rest API 시작하기 Controller 작성

목차 Spring Rest API - Spring Boot Swagger 사용하기 Spring Rest API - ExceptionHandling Spring Rest API - HTTP Status Code 다루기 Spring Rest API - 도메인 및 서비스 로직 작성하기 Spring Rest API - Rest API 시작하기 Controller 작성 Spring Boot Rest API - Rest API 시작하기 Controller 작성@RestControllerpublic class HelloWorldController { @GetMapping("/hello-world") public String Hello(){ return "Hello World"; } // SpringBoot에서는 HelloWorldBean이라는 객체를 JSON타입의 형태로 반환해준다. @GetMapping("/hello-world-bean/") public HelloWorldBean helloWorldBean(){ return new HelloWorldBean("Hello World"); } @GetMapping("/hello-world-bean/path-variable/{name}") public HelloWorldBean helloWorldBean(@PathVariable String name){ return new HelloWorldBean(String.format("Hello World, %s", name)); }} HelloWorldBean 클래스 생성@Data@NoArgsConstructor@AllArgsConstructorpublic class HelloWorldBean { private String message;} 테스트 코드 작성 MockMvc 객체를 이용해 각 Controller에 대한 Test 코드를 작성한다. MockMvc 객체의 반환 값으로는 ResultActions 를 이용해 받는다. ResultActions 객체내 andExpect 메소드를 이용해 요청이 정상적(200) 으로 수행 됐는지 반환 값이 정상적으로 왔는지 검증한다. @Testpublic void Hello_World가_리턴된다() throws Exception{ ResultActions actions = mockMvc.perform(get("/hello-world")); actions .andExpect(status().isOk()) .andExpect(content().string("Hello World")) .andDo(print()) ;}

0

Spring Security OAuth2를 이용한 로그인 구현 - 사용자 정보 가져오기

목차 Spring Security OAuth2 - Handler Spring Security OAuth2 - Login 페이지 Customizing 하기 Spring Security OAuth2를 이용한 로그인 구현 - 사용자 정보 가져오기 Spring Security OAuth2를 이용한 로그인 구현 - Spring boot OAuth2 인증 살펴보기 Spring Security OAuth2를 이용한 로그인 구현 - OAuth2를 이용한 인증 사용하기 Google OAuth2 인증 방식 이해하기 OAuth2를 이용한 로그인 구현 이해하기 2. Resource Server로부터 사용자 정보 가져오기Spring Security 설정하기OAuth2 인증을 마친 후에 Resource Server로부터 사용자 정보를 가져오기 위해서는 UserInfo EndPoint에 접근할 필요가 있다. HttpSecurity객체의 oauth2Login().userInfoEndpoint().userService() 메소드를 이용해서 UserInfo EndPoint로부터 사용자 정보를 가져올 Service를 등록한다. @EnableWebSecurity@RequiredArgsConstructorpublic class SecurityConfig extends WebSecurityConfigurerAdapter { private final CustomOAuth2UserService customOAuth2UserService; @Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/**").authorizeRequests() .antMatchers("/").permitAll() .anyRequest().authenticated(); http .oauth2Login() .userInfoEndpoint() .userService(customOAuth2UserService); }} 스프링에서 기본적으로 제공하는 OAuth2ProviderGoogle, Facebook, Github 등을 통해 OAuth2인증하기 위한 기본적인 설정값들이 들어가 있다. 해당 정보를 통해 ClientRegistration 객체를 생성한다. authorizationUri 인증을 진행하기 위해 사용하는 URI tokenUri Resource server로부터 access token을 받기 위해 사용하는 URI jwkSetUri token의 유효성(서명)을 확인할 수 있는 public key(JSON Web Key)를 받을 수 있는 URI userInfoUri Resource Server(ex. Google)로부터 사용자 정보를 가져오기 위한 URI userNameAttributeName Resource server가 제공하는 id값 clientName Resource Server 이름(client Name을 사용할 때도 있다.)