

⇒ 위와 같은 주소 기능을 다음과 같이 구현

⇒ 다양한 예제가 있지만, 사용자가 선택한 값 이용하기 적용
<input type="text" id="sample6_postcode" placeholder="우편번호">
<input type="button" onclick="sample6_execDaumPostcode()" value="우편번호 찾기"><br>
<input type="text" id="sample6_address" placeholder="주소"><br>
<input type="text" id="sample6_detailAddress" placeholder="상세주소">
<input type="text" id="sample6_extraAddress" placeholder="참고항목">
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<script>
function sample6_execDaumPostcode() {
new daum.Postcode({
oncomplete: function(data) {
// 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
// 각 주소의 노출 규칙에 따라 주소를 조합한다.
// 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
var addr = ''; // 주소 변수
var extraAddr = ''; // 참고항목 변수
//사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
addr = data.roadAddress;
} else { // 사용자가 지번 주소를 선택했을 경우(J)
addr = data.jibunAddress;
}
// 사용자가 선택한 주소가 도로명 타입일때 참고항목을 조합한다.
if(data.userSelectedType === 'R'){
// 법정동명이 있을 경우 추가한다. (법정리는 제외)
// 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.
if(data.bname !== '' && /[동|로|가]$/g.test(data.bname)){
extraAddr += data.bname;
}
// 건물명이 있고, 공동주택일 경우 추가한다.
if(data.buildingName !== '' && data.apartment === 'Y'){
extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
}
// 표시할 참고항목이 있을 경우, 괄호까지 추가한 최종 문자열을 만든다.
if(extraAddr !== ''){
extraAddr = ' (' + extraAddr + ')';
}
// 조합된 참고항목을 해당 필드에 넣는다.
document.getElementById("sample6_extraAddress").value = extraAddr;
} else {
document.getElementById("sample6_extraAddress").value = '';
}
// 우편번호와 주소 정보를 해당 필드에 넣는다.
document.getElementById('sample6_postcode').value = data.zonecode;
document.getElementById("sample6_address").value = addr;
// 커서를 상세주소 필드로 이동한다.
document.getElementById("sample6_detailAddress").focus();
}
}).open();
}
</script><script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
// 다음 주소 API
function execDaumPostcode() {
new daum.Postcode({
oncomplete: function (data) {
// 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
// 각 주소의 노출 규칙에 따라 주소를 조합한다.
// 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
var addr = ""; // 주소 변수
//사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
if (data.userSelectedType === "R") {
// 사용자가 도로명 주소를 선택했을 경우
addr = data.roadAddress;
} else {
// 사용자가 지번 주소를 선택했을 경우(J)
addr = data.jibunAddress;
}
// 우편번호와 주소 정보를 해당 필드에 넣는다.
document.getElementById("postcode").value = data.zonecode;
document.getElementById("address").value = addr;
// 커서를 상세주소 필드로 이동한다.
document.getElementById("detailAddress").focus();
},
}).open();
}
⇒ 참고항목은 구현하지 않았기 때문에, 참고항목 관련 코드를 삭제하였다.


⇒ 위와 같이 반영되는 것을 확인할 수있다.
@SessionAttributes의 역할
* - Model에 추가된 속성 중 key 값이 일치하는 속성을 session scope로 변경하는 어노테이션
* - 클래스 상단에 @SessionAttributes({ "loginMember" })
@SessionAttribute의 역할
* - @SessionAttributes를 통해 session에 등록된 속성을 꺼내올 때 사용하는 어노테이션
* - 메서드의 매개변수
// ex)
@GetMapping("info") // /myPage/info GET 방식 요청 매핑
public String info(@SessionAttribute("loginMember") Member loginMember, Model model) {
.
.
}


⇒ 새로고침이 되면서 session이 초기화 되면서 session이 사라짐
⇒ 또한, 다른 사용자가 접근할 수도 있기 때문에 막아줘야 함

package edu.kh.project.common.filter;
import java.io.IOException;
import edu.kh.project.member.model.dto.Member;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/*
* Filter : 요청, 응답 시 걸러내거나 추가할 수 있는 객체
*
* [필터 클래스 생성 방법]
* 1. jakarta.servlet.Filrer 인터페이스 상속받기
* 2. doFilter() 메서드 오버라이딩
*
* */
// 로그인이 되어있지 않은 경우, 특정 페이지를 접근할 수 없도록 필터링하기
public class LoginFilter implements Filter {
// 필터 동작을 정의하는 메서드
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// ServletRequest : HttpServletRequest의 부모타입
// ServletResponse : HttpServletResponse 의 부모타입
// session이 필요함 -> 왜 필요한가? -> loginMember가 session에 담기기 때문
// HttpServletRequest 형태(자식형태)로 다운캐스팅
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 현재 요청의 URI를 가져옴
String path = req.getRequestURI(); // /myPage/profile
// 요청 URI가 "/myPage/profile"로 시작하는지 확인
if (path.startsWith("/myPage/profile/")) {
// 필터를 통과하도록 함
// FilterChain : 다음 필터로 체이닝, 또는 다음 필터가 없다면 DispatcherServler로 보냄
// 요청 URI 값이 "/myPage/profile"로 시작하는지 확인
// 해당 요청은 막아주지 않고 통과시킬 것
// 파일 업로드할 때 문제가 발생함
// 마이페이지에서 각종 이미지는 서버에 요청을 보내서 가져오는 것
// 그리고나서 화면에 뿌려주는 것
// 근데, 프로필 이미지는 서버에 요청을 보낼 때, /myPage/profile/스폰지밥.jpg을 사용할 것
// 로그인을 하지 않았어도, 게시판 글을 확인할 수 있고, 이미지를 볼 수 있어야 함
// 하지만, 로그인이 되어있지 않은 상태에서 다른 유저의 프로필 이미지가 다 깨짐
// 이미지를 가져오는 서버 매핑이 /myPage/profile...로 시작함
chain.doFilter(request, response);
// DispatcherServler로 보냄
// 즉, 다음 필터가 없다는 것
// 필터를 통과한 후 아래에 문장이 실행되지 않도록 return해줌
return;
}
// session 객체 얻어오기
HttpSession session = req.getSession();
// 세션에서 로그인한 회원 정보를 꺼내옴
// loginMember가 있는지, null인지 확인하기
if (session.getAttribute("loginMember") == null) {
// 로그인이 되어있지 않은 상태를 의미
resp.sendRedirect("/loginError");
} else {
// -> 로그인이 되어 있는 상태
// 다음 필터로 이동하던지, 혹은 다음 필터가 없다면 DispatcherServlet로 요청과 응답객체를 전달
chain.doFilter(request, response);
}
}
}
package edu.kh.project.common.config;
import java.util.Arrays;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import edu.kh.project.common.filter.LoginFilter;
@Configuration // 서버가 켜질 때 클래스 내 모든 메서드가 실행되도록 하는 어노테이션 + 빈등록
public class FilterConfig {
// 언제 LoginFilter가 동작할지 정의해주면 됌
// 만들어 놓은 LoginFilter 클래스가 언제 적용될 지 설정하는 것
@Bean // 반환된 객체를 Bean으로 등록 :
// LoginFilter로 타입을 제한한 객체를 Bean으로 등록한다.
public FilterRegistrationBean<LoginFilter> loginFilter() {
// FilterRegistrationBean : 필터를 Bean으로 등록하는 객체
FilterRegistrationBean<LoginFilter> filter = new FilterRegistrationBean<>();
// 사용할 필터 객체 세팅
filter.setFilter(new LoginFilter());
// 필터가 동작할 URL을 세팅
// /myPage/* : /myPage로 시작하는 모든 요청
String[] filteringURL = {"/myPage/*", "/chatting/*", "/editBoard/*"};
// String[]을 List 변환
// Arrays.asList(배열) -> List 변환
filter.setUrlPatterns(Arrays.asList(filteringURL));
// 필터 이름 지정
filter.setName("loginFilter");
// 필터 순서 지정
filter.setOrder(1);
return filter; // 반환된 객체가 Bean 등록
}
}

⇒ Filter를 통해 막아놓은 곳을 접속하면 위와 같이 alert창이 뜨면서 막아준다.
이미지 요청 경로 : /myPage/profile/2025
로그인 여부 관련이 없는 요청 /myPage/profile/ → (통과)
프로필 변경 화면 이동 요청 : /myPage/profile → /myPage/* (LoginFilter에 의해 걸러짐)