네이버 쇼핑 최저가 저장
유투브 시연
https://www.youtube.com/watch?v=6OemCC6xQdw&t=54s
깃 소스 저장
https://github.com/MyoungSoo7/shopping_lowprice
(인텔리제이, 자바11, 스프링부트2.7, 그래들,타임리프, 스피링시큐리티,mysql ,h2database)
jwt 설정
package com.sparta.springcore.security;
import com.sparta.springcore.security.filter.FormLoginFilter;
import com.sparta.springcore.security.filter.JwtAuthFilter;
import com.sparta.springcore.security.jwt.HeaderTokenExtractor;
import com.sparta.springcore.security.provider.FormLoginAuthProvider;
import com.sparta.springcore.security.provider.JWTAuthProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
@EnableGlobalMethodSecurity(securedEnabled = true) // @Secured 어노테이션 활성화
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final JWTAuthProvider jwtAuthProvider;
private final HeaderTokenExtractor headerTokenExtractor;
public WebSecurityConfig(
JWTAuthProvider jwtAuthProvider,
HeaderTokenExtractor headerTokenExtractor
) {
this.jwtAuthProvider = jwtAuthProvider;
this.headerTokenExtractor = headerTokenExtractor;
}
@Bean
public BCryptPasswordEncoder encodePassword() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(AuthenticationManagerBuilder auth) {
auth
.authenticationProvider(formLoginAuthProvider())
.authenticationProvider(jwtAuthProvider);
}
@Override
public void configure(WebSecurity web) {
// h2-console 사용에 대한 허용 (CSRF, FrameOptions 무시)
web
.ignoring()
.antMatchers("/h2-console/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// 서버에서 인증은 JWT로 인증하기 때문에 Session의 생성을 막습니다.
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
/*
* 1.
* UsernamePasswordAuthenticationFilter 이전에 FormLoginFilter, JwtFilter 를 등록합니다.
* FormLoginFilter : 로그인 인증을 실시합니다.
* JwtFilter : 서버에 접근시 JWT 확인 후 인증을 실시합니다.
*/
http
.addFilterBefore(formLoginFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests()
.anyRequest()
.permitAll()
.and()
// [로그아웃 기능]
.logout()
// 로그아웃 요청 처리 URL
.logoutUrl("/user/logout")
.permitAll()
.and()
.exceptionHandling()
// "접근 불가" 페이지 URL 설정
.accessDeniedPage("/forbidden.html");
}
@Bean
public FormLoginFilter formLoginFilter() throws Exception {
FormLoginFilter formLoginFilter = new FormLoginFilter(authenticationManager());
formLoginFilter.setFilterProcessesUrl("/user/login");
formLoginFilter.setAuthenticationSuccessHandler(formLoginSuccessHandler());
formLoginFilter.afterPropertiesSet();
return formLoginFilter;
}
@Bean
public FormLoginSuccessHandler formLoginSuccessHandler() {
return new FormLoginSuccessHandler();
}
@Bean
public FormLoginAuthProvider formLoginAuthProvider() {
return new FormLoginAuthProvider(encodePassword());
}
private JwtAuthFilter jwtFilter() throws Exception {
List<String> skipPathList = new ArrayList<>();
// Static 정보 접근 허용
skipPathList.add("GET,/images/**");
skipPathList.add("GET,/css/**");
// h2-console 허용
skipPathList.add("GET,/h2-console/**");
skipPathList.add("POST,/h2-console/**");
// 회원 관리 API 허용
skipPathList.add("GET,/user/**");
skipPathList.add("POST,/user/signup");
skipPathList.add("GET,/");
skipPathList.add("GET,/basic.js");
skipPathList.add("GET,/favicon.ico");
FilterSkipMatcher matcher = new FilterSkipMatcher(
skipPathList,
"/**"
);
JwtAuthFilter filter = new JwtAuthFilter(
matcher,
headerTokenExtractor
);
filter.setAuthenticationManager(super.authenticationManagerBean());
return filter;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
최저가 쇼핑 리스트
10개 패키지 ( 2개 테스트용)
aop : 부가기능( api 사용시간)
controller : api, folder. home, itemsearch, product, user, username 제어 7개
dto (data transfer object) : foler, item, kakaouserinfo, productMyPriceRequest , productRequest, SingupRequestDto
exception : 예외( Error, RestAPIException )
model (DB테이블 역할 7개) : ApiUseTime, Folder, Product ,Timestamped, UserName, UserRoleENum, Users
repository : DB 연결 역할 5개( apiusetime, folder, product, username, user)
sercurity ( 사용자 보안)
@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
@EnableGlobalMethodSecurity(securedEnabled = true) // @Secured 어노테이션 활성화
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder encodePassword() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) {
// h2-console 사용에 대한 허용 (CSRF, FrameOptions 무시)
web
.ignoring()
.antMatchers("/h2-console/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
// image 폴더를 login 없이 허용
.antMatchers("/images/**").permitAll()
// css 폴더를 login 없이 허용
.antMatchers("/css/**").permitAll()
// 회원 관리 처리 API 전부를 login 없이 허용
.antMatchers("/user/**").permitAll()
// 그 외 어떤 요청이든 '인증'
.anyRequest().authenticated()
.and()
// [로그인 기능]
.formLogin()
// 로그인 View 제공 (GET /user/login)
.loginPage("/user/login")
// 로그인 처리 (POST /user/login)
.loginProcessingUrl("/user/login")
// 로그인 처리 후 성공 시 URL
.defaultSuccessUrl("/")
// 로그인 처리 후 실패 시 URL
.failureUrl("/user/login?error")
.permitAll()
.and()
// [로그아웃 기능]
.logout()
// 로그아웃 요청 처리 URL
.logoutUrl("/user/logout")
.permitAll()
.and()
.exceptionHandling()
// "접근 불가" 페이지 URL 설정
.accessDeniedPage("/forbidden.html");
}
}
service : folder, itemsearch, kakaouser, product , username, user 6개
utils : 스케줄러
validator : 유효성체크 (product ,url)
테이블 구조 7개
회원가입 시작
가입후 로그인
로그인 화면
네이버 쇼핑 API로 레스트빈 불러오기
` 를 이용해서 입력값을 query 파라미터로 검색해 옵니다.
RestTemplate을 사용하여
HttpEntity에 body,hearder 담아서=>[ body(String)와 HttpHeards(네이버클라이언트id,secret) 담아서 보내고(exchange)]
ResponseEntity<String>으로 받아옵니다.
// 네이버 쇼핑 API 호출에 필요한 Header, Body 정리
RestTemplate rest = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("X-Naver-Client-Id", "");
headers.add("X-Naver-Client-Secret", "");
String body = "";
HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
// 네이버 쇼핑 API 호출 결과 -> naverApiResponseJson (JSON 형태)
ResponseEntity<String> responseEntity
= rest.exchange("https://openapi.naver.com/v1/search/shop.json?query=" + query,
HttpMethod.GET, requestEntity, String.class);
String naverApiResponseJson = responseEntity.getBody();
ResponseEntity의 body 만 String 타입으로 받으면
아이템 목록이 나옵니다.
String naverApiResponseJson = responseEntity.getBody();
해당 String 을 우리에게 필요한 데이터만 추출해서 return 합니다.
저장하면 하기와 같이 나옵니다.
폴더 추가 및 폴더에 아이템을 추가 할 수 있다.
폴더는 해당 유저에 한하여 폴더추가 시키고
또 아이템은 해당유저의 폴더에 한하여 추가한다.
관리자 회원가입시 관리자는 특정패스워드 입
관리자는 모든 사용자의 쇼핑목록을 볼수 있다.
'4차산업혁명의 일꾼 > Java&Spring웹개발과 서버 컴퓨터' 카테고리의 다른 글
실용주의 프로그래머 [8장 46 챕터] (0) | 2023.03.22 |
---|---|
클린아키텍쳐 - 소프트웨어의 구조와 설계의 원칙[7부 34장] (0) | 2023.03.21 |
Effective Java 이펙티브 자바 정리[조슈아 블로치] (0) | 2023.03.20 |
MyBatis로 게시판 만들기 (0) | 2023.03.20 |
Spring DI와 AOP (0) | 2023.03.19 |