1. 어제 이어서 로그인, 마이 페이지
1) 인터셉터
- 위와 같은 단점으로 인터셉터 개념 사용
- 인터셉터는 컨트롤러 들어가기 직전에 요청을 가로채서 검사를 해줄 수 있는 기능
- 필터와 인터셉터의 개념은 똑같으나 위치가 다르다는 차이점이 존재함
- 부가적으로 AOP는 필터 개념은 아니고, 컨트롤러나 메서드가 실행될 때마다 검사를 하고 싶을 때 사용할 수 있는 기능
- 로그, 트랙잭션 같은 개념이 AOP에 속함
- 인터셉터의 사용은 HandlerInterceptor 인터페이스(2번째 사진에 3, 6, 9번-3,6만 자주 사용 됨)를 상속 받아 사용함.
- 3번은 진입 전에 요청을 받아서 확인 하는 것, 6번은 컨트롤러가 수행 되고 나서 내가 검사하고 싶은 기능이 있으면 사용, 9번은 마지막(최종 뷰로 넘어가기 전에 검사할 수 있음-굳이 사용하지는 않음)
2) 인터셉터 설정
* 적용 - UserAuthHandler, webconfig, UserSuccessHandler
- UserAuthHandler
package com.simple.basic.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
public class UserAuthHandler implements HandlerInterceptor {
/*
* 1. HandlerIntercetpor를 상속 받습니다.
*
* preHandle - 컨트롤러 진입 전에 실행
* postHandle - 컨트롤러 수행 후에 실행
* afterCompletion - 화면으로 가기 직전에 수행
*
* 2. 인터셉터 클래스를 bean으로 등록
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("인터셉터 실행");
//현재 세션을 얻음
HttpSession session = request.getSession();
String user_id = (String)session.getAttribute("user_id");
if(user_id == null) { //로그인이 안됨
response.sendRedirect( request.getContextPath() + "/user/login" ); //로그인 페이지로 리디렉션
return false; //컨트롤러를 실행하지 않음
}
return true; //컨트롤러 실행
}
}
- webconfig
package com.simple.basic.config;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.simple.basic.controller.HomeController;
import com.simple.basic.util.UserAuthHandler;
import com.simple.basic.util.UserSuccessHandler;
@Configuration //개별적인 스프링 빈 설정 파일
public class WebConfig implements WebMvcConfigurer {
//빈을 보관하고 있는 장소 (스프링 컨테이너)
/*
@Autowired
ApplicationContext applicationContext;
//properties파일에 선언된 변수를 바로 참조
@Value("${server.port}")
String port;
@Bean //해당 메서드 실행하게됨
public void test() {
TestBean t = applicationContext.getBean(TestBean.class);
System.out.println(t);
HomeController h = applicationContext.getBean(HomeController.class);
System.out.println(h);
int c = applicationContext.getBeanDefinitionCount();
System.out.println("빈의개수:" + c);
System.out.println("properties에 선언된값:" + port);
}
@Bean //해당 메서드 실행하게됨
public TestBean testBean() {
return new TestBean(); //빈으로 등록
}
*/
//프리 핸들러
@Bean
public UserAuthHandler userAuthHandler() {
return new UserAuthHandler();
}
//포스트 핸들러
@Bean
public UserSuccessHandler userSuccessHandler() {
return new UserSuccessHandler();
}
//WebMvcConfigurer클래스가 제공해주는 인터셉터 추가 함수
@Override
public void addInterceptors(InterceptorRegistry registry) {
//프리 핸들러
registry.addInterceptor(userAuthHandler() )
// .addPathPatterns( Arrays.asList("경로", "경로", "경로", "경로"))
.addPathPatterns("/user/*") //패스 경로 포함
.excludePathPatterns("/user/login"); //제외 하고 싶은 경로(패스 경로 제외)
//경로 별로 인터셉터를 다르게 등록
//포스트 핸들러
registry.addInterceptor( userSuccessHandler() )
.addPathPatterns("/user/*");
}
}
- UserSuccessHandler
package com.simple.basic.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class UserSuccessHandler implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//modelAndView은 컨트롤러에서 model에 담은 데이터도 확인이 가능합니다.
System.out.println("포스트 핸들러:" + request.getRequestURI());
}
}
- bootmyweb에 적용해보기
* Webconfig, UserController, UserAuthHandler, menuHandler, basiclayout
- Webconfig
package com.coding404.myweb.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.coding404.myweb.util.interceptor.MenuHandler;
import com.coding404.myweb.util.interceptor.UserAuthHandler;
@Configuration //스프링 설정 파일
public class WebConfig implements WebMvcConfigurer {
//프리 핸들러
@Bean
public UserAuthHandler userAuthHandler() {
return new UserAuthHandler();
}
//포스트 핸들러
@Bean
public MenuHandler menuHandler() {
return new MenuHandler();
}
//인터셉터 추가
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( userAuthHandler() )
.addPathPatterns("/main")
.addPathPatterns("/product/*")
.addPathPatterns("/user/*")
.excludePathPatterns("/user/login")
.excludePathPatterns("/user/join");
// .addPathPatterns("/**")
// .excludePathPatterns("/user/login")
// .excludePathPatterns("/user/join")
// .excludePathPatterns("/js/*")
// .excludePathPatterns("/css/*")
// .excludePathPatterns("/img/*");
//REST API 패스에서 제외
registry.addInterceptor(menuHandler() )
.addPathPatterns("/main")
.addPathPatterns("/product/*")
.addPathPatterns("/user/*");
}
}
- UserController
package com.coding404.myweb.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/join")
public String join() {
return "user/join";
}
@GetMapping("/login")
public String login() {
return "user/login";
}
@GetMapping("/userDetail")
public String userDetail() {
return "user/userDetail";
}
}
- UserAuthHandler
package com.coding404.myweb.util.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
public class UserAuthHandler implements HandlerInterceptor {
/*
* 1. HandlerIntercetpor를 상속 받습니다.
*
* preHandle - 컨트롤러 진입 전에 실행
* postHandle - 컨트롤러 수행 후에 실행
* afterCompletion - 화면으로 가기 직전에 수행
*
* 2. 인터셉터 클래스를 bean으로 등록
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("인터셉터 실행");
//현재 세션을 얻음
HttpSession session = request.getSession();
String user_id = (String)session.getAttribute("user_id");
if(user_id == null) { //로그인이 안됨
response.sendRedirect( request.getContextPath() + "/user/login" ); //로그인 페이지로 리디렉션
return false; //컨트롤러를 실행하지 않음
}
return true; //컨트롤러 실행
}
}
- menuhandler
package com.coding404.myweb.util.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.coding404.myweb.product.service.ProductMapper;
public class MenuHandler implements HandlerInterceptor {
@Autowired
private ProductMapper productMapper;
//메뉴 핸들러
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
String uri = request.getRequestURI();
request.setAttribute("uri", uri);
}
}
- basiclayout - 맨 밑에 script 추가(확인할 때 인터셉터 잠깐 주석처리)하고 위에 밑에 사진 부분 추가
<script th:inline="javascript">
/*
메뉴선택유지 -
sub_menu에 display:block.
sub_menu > a링크에 on클래스.
sub_menu_toggle > a에 sub_menu_select클래스.
*/
var menu = JSON.parse('[[${uri}]]'); //postHandler에서 보내주는 uri
//1번
//$("a[href*='" + menu + "']").addClass("on");
//console.log($("a[href*='" + menu + "']") );
//2번
$(".sub_menu a").each(function(index, item) {
//console.log(index, item)
//console.log( $(item) )
//console.log ( $(item).attr("href") )
//href에 uri값이 들어있는지 확인
if( $(item).attr("href").includes(menu) ) {
$(item).addClass("on"); //a태그에 on클래스 추가
$(item).closest(".sub_menu").css("display", "block");
$(item).closest(".sub_menu").prev().addClass("sub_menu_select");
}
})
</script>
2. 자바측 API 통신(vscode에서 ajax → js-index05.html)
- login 창에 제이쿼리 링크 추가
- login.html에 맨 마지막에 script 부분 추가
<script>
$(".kakaoBtn").click(function(){
http://127.0.0.1:8484/user/kakao
//uri에는 web 사이트 도메인에 추가한 주소 + user/kakao
location.href="https://kauth.kakao.com/oauth/authorize?client_id=본인의 restAPI &redirect_uri=http://127.0.0.1:8484/user/kakao&response_type=code";
})
</script>
- userController에 추가
//카카오 redirect_uri 값 추가
@GetMapping("/kakao")
public String kakao(@RequestParam("code") String code) {
System.out.println(code);
return null;
}
- 본인 포트 번호 확인해서 넣을 것
* 하고 나서 카카오 디벨로퍼 로그아웃을 해야지 로그인 창으로 넘어감
- kakao API에 @Component - 카카오라는 이름으로 빈 생성
- userController에 Autowired 걸고 kakao 변수 선언
@Autowired
private KakaoAPI kakao;
* KakaoAPI
package com.coding404.myweb.util;
import org.springframework.stereotype.Component;
@Component("kakao")
public class KakaoAPI {
//토큰 발급 기능
public String getAccessToken(String code) {
return null;
}
}
- 카카오 디벨로퍼에서 토큰 받기
package com.coding404.myweb.util;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.springframework.stereotype.Component;
@Component("kakao")
public class KakaoAPI {
//토큰 발급 기능
public String getAccessToken(String code) {
//post의 폼데이터 형식 키=값&키=값..
String requestURL = "https://kauth.kakao.com/oauth/token";
String redirect_url ="http://127.0.0.1:8484/user/kakao";
String data = "grant_type=authorization_code"
+ "&client_id=본인의 restAPI 주소"
+ "&redirect_uri=" + redirect_url
+ "&code=" + code;
try {
URL url = new URL(requestURL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST"); //포스트 형식
conn.setDoOutput(true); //카카오 서버로부터 데이터 응답을 허용
//데이터 전송을 위한 클래스
// OutputStream out = conn.getOutputStream();
// OutputStreamWriter osw = new OutputStreamWriter(out);
// BufferedWriter br = new BufferedWriter(osw);
BufferedWriter br = new BufferedWriter( new OutputStreamWriter( conn.getOutputStream()));
br.write(data); //쓰고
br.flush(); //밀어내고
//응답 결과를 conn 객체로 받음
System.out.println( conn.getResponseCode() );
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- 그 다음에 컨트롤러에서 확인해볼 것
//카카오 redirect_uri 값 추가
@GetMapping("/kakao")
public String kakao(@RequestParam("code") String code) {
System.out.println("인가코드:" + code);
String token = Kakao.getAccessToken(code);
return "redirect:/main";
}
- 다시 kakaoAPI
//응답 결과를 conn 객체로 받음
System.out.println( "요청 결과:" + conn.getResponseCode() );
if(conn.getResponseCode() == 200) { //요청이 성공
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream()));
String result ="";
String str = null;
while( (str = br.readLine() ) != null) { //데이터 한줄씩 읽음 - 읽을 값이 없다면 null을 반환
result += str;
}
System.out.println(result);
}
//json 데이터 분해
JsonParser json = new JsonParser(); //com.google.~
JsonElement element = json.parse(result); //json 데이터 전달
JsonObject obj = element.getAsJsonObject(); //json 오브젝트 형변환
String access_token = obj.get("access_token").getAsString();
String refresh_token = obj.get("refresh_token").getAsString();
//카카오 redirect_uri 값 추가
@GetMapping("/kakao")
public String kakao(@RequestParam("code") String code) {
System.out.println("인가코드:" + code);
String token = Kakao.getAccessToken(code);
System.out.println("어세스 토큰:"+ token);
return "redirect:/main";
}
- 이제 토큰 기반으로 유저 정보 얻기
- kakaoapi에 추가
//토큰 기반으로 유저 정보 얻기
public Map<String, Object> getUserInfo(String access_token){
String requestURL = "https://kapi.kakao.com/v2/user/me";
try {
URL url = new URL(requestURL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST"); //포스트 형식
conn.setDoOutput(true); //카카오 서버로부터 데이터 응답을 허용
//헤더에 토큰 정보를 추가
conn.setRequestProperty("Authorization", "Bearer " + access_token);
System.out.println("토큰 요청 결과:" + conn.getResponseCode());
if(conn.getResponseCode() == 200) { //사용자 데이터 요청 성공
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream()));
String result ="";
String str = null;
while( (str = br.readLine() ) != null) { //데이터 한줄씩 읽음 - 읽을 값이 없다면 null을 반환
result += str;
}
System.out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- 컨트롤러에서 출력
//카카오 redirect_uri 값 추가
@GetMapping("/kakao")
public String kakao(@RequestParam("code") String code) {
System.out.println("인가코드:" + code);
String token = Kakao.getAccessToken(code);
System.out.println("어세스 토큰:"+ token);
Map<String, Object> map = Kakao.getUserInfo(token);
return "redirect:/main";
}
}
- kakaoAPI
//토큰 기반으로 유저 정보 얻기
public Map<String, Object> getUserInfo(String access_token){
//데이터를 저장할 map
Map<String, Object> map = new HashMap<>();
String requestURL = "https://kapi.kakao.com/v2/user/me";
try {
URL url = new URL(requestURL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST"); //포스트 형식
conn.setDoOutput(true); //카카오 서버로부터 데이터 응답을 허용
//헤더에 토큰 정보를 추가
conn.setRequestProperty("Authorization", "Bearer " + access_token);
System.out.println("토큰 요청 결과:" + conn.getResponseCode());
if(conn.getResponseCode() == 200) { //사용자 데이터 요청 성공
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream()));
String result ="";
String str = null;
while( (str = br.readLine() ) != null) { //데이터 한줄씩 읽음 - 읽을 값이 없다면 null을 반환
result += str;
}
System.out.println(result);
JsonParser json = new JsonParser();
JsonElement element = json.parse(result);
//json에서 key를 꺼내고, 다시 key를 꺼낸다.
JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject();
JsonObject kakao_account = element.getAsJsonObject().get("kakao_account").getAsJsonObject();
String nickname = properties.getAsJsonObject().get("nickname").getAsString();
String email = kakao_account.getAsJsonObject().get("email").getAsString();
map.put("nickname", nickname);
map.put("email", email);
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
- 하고 컨트롤러
'TIL > Spring boot' 카테고리의 다른 글
windows에서 java 환경변수 설정하기 (0) | 2023.06.12 |
---|---|
day91-spring boot (0) | 2023.02.22 |
day90-spring boot (0) | 2023.02.21 |
day88-spring boot (0) | 2023.02.17 |
day86-spring boot (0) | 2023.02.16 |