first commit

This commit is contained in:
2026-03-06 14:20:30 +09:00
commit 4eefcfc0a8
21 changed files with 1261 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
package com.paynuri.common.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 로깅 인터셉터 예제
* 필요시 WebConfig에서 등록하여 사용
*/
@Slf4j
@Component
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.debug("[preHandle][{}] {}", request.getMethod(), request.getRequestURI());
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.debug("[postHandle][{}] {}", request.getMethod(), request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
log.debug("[afterCompletion][{}] {} - {}ms", request.getMethod(), request.getRequestURI(), executeTime);
if (ex != null) {
log.error("[afterCompletion] Exception: ", ex);
}
}
}

View File

@@ -0,0 +1,69 @@
package com.paynuri.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
/**
* Redis Session Configuration
*/
@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
/**
* Development Profile Session Configuration
*/
@Configuration
@Profile("dev")
@EnableRedisHttpSession(redisNamespace = "spring:session:dev")
static class DevRedisSessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("DEV_SESSION");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}
}
/**
* Test Profile Session Configuration
*/
@Configuration
@Profile("test")
@EnableRedisHttpSession(redisNamespace = "spring:session:test")
static class TestRedisSessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("TEST_SESSION");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}
}
/**
* Production Profile Session Configuration
*/
@Configuration
@Profile("real")
@EnableRedisHttpSession(redisNamespace = "spring:session:real")
static class RealRedisSessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSION");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
serializer.setUseHttpOnlyCookie(true);
serializer.setUseSecureCookie(true);
return serializer;
}
}
}

View File

@@ -0,0 +1,40 @@
package com.paynuri.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// CSRF 설정
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
)
// 요청 인증 설정
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/css/**", "/js/**", "/images/**", "/favicon.ico").permitAll()
.requestMatchers("/", "/home", "/public/**").permitAll()
.requestMatchers("/session/**", "/session").permitAll()
.anyRequest().authenticated()
)
// 로그인 설정
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
// 로그아웃 설정
.logout(logout -> logout
.permitAll()
);
return http.build();
}
}

View File

@@ -0,0 +1,36 @@
package com.paynuri.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 정적 리소스 핸들러 설정
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/")
.setCachePeriod(3600);
registry.addResourceHandler("/uploads/**")
.addResourceLocations("file:uploads/")
.setCachePeriod(3600);
}
/**
* Interceptor 설정
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 필요한 경우 Interceptor 추가
// registry.addInterceptor(new LoggingInterceptor())
// .addPathPatterns("/**")
// .excludePathPatterns("/static/**", "/css/**", "/js/**", "/images/**");
}
}

View File

@@ -0,0 +1,42 @@
package com.paynuri.www;
import jakarta.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class SessionController {
@GetMapping("/session")
public String sessionPage(HttpSession session, Model model) {
String username = (String) session.getAttribute("username");
Integer visitCount = (Integer) session.getAttribute("visitCount");
if (visitCount == null) {
visitCount = 0;
}
visitCount++;
session.setAttribute("visitCount", visitCount);
model.addAttribute("username", username);
model.addAttribute("visitCount", visitCount);
model.addAttribute("sessionId", session.getId());
return "session-example";
}
@PostMapping("/session/login")
public String login(@RequestParam String username, HttpSession session) {
session.setAttribute("username", username);
return "redirect:/session";
}
@PostMapping("/session/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/session";
}
}

View File

@@ -0,0 +1,13 @@
package com.paynuri.www;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WwwApplication {
public static void main(String[] args) {
SpringApplication.run(WwwApplication.class, args);
}
}