필자가 처음 2017년에 스프링을 배울 때만 해도, 전공자들이 스프링을 잘 모르는 것을 보고 이상히 여겼다. 스프링이 신기술인가 했지만... 교수님들이 가르치기 어려운 그런 거였다. 이미 많이 쓰이고 있었는데.. 자바 1.6~7이 한창이던 시절 자바 1.8로 배웠다. 날짜, 스트림, 람다 등이 주로 변화였으나 사실 자바 자체도 제대로 몰랐기 때문에 이런 버전의 변천이 어떤 영향이 있는지도 몰랐다.
그래서 예전에 모델2에서 스프링으로 바뀌었고 JPA도 있는데, 학원에서 배웠던 교재를 다시 복습해 보니 신기술로 생각한 JPA도 이미 그 책에 있었다. 다만 비교적 최신기술이라 실무에서 잘 쓰이지 않았을 뿐이다. 지금은 7년여가 지나 대세가 되었다. 진리탐구니 결혼이니 아이키우기니 병행하면서 지금까지 왔는데, 이제는 좀더 진지하게 고급개발자가 되기 위하여 기초공사를 튼튼히 하고 싶다.
스프링은 모델,컨트롤러, 뷰가 있는데, 이 MVC로 만든것은 보통 웹 HTTP는 무상태성을 띄어서 요청이 오면 다음 요청은 또 별개다. 그래서 요청을 처리하기 위해 디스패처 서블릿이 요청을 잡아서 핸들러 매핑을 통해 컨트롤러에 매핑시키는 것이다. 그리고 나서 DAO니, VO니 데이터를 담을 통에다가 모델을 만들어 마이바티스 매핑을 통해 DB에서 쿼리를 조회해 오고 그것을 뷰리졸버를 통하여 프론트 단에 뿌려주는 구조 였다.
이렇게 웹과 소통하는 컨트롤러, DB와 소통하는 모델, 그리고 UI와 소통하는 뷰를 나누어서 MVC 패턴이라고 했던 것이다. 이것을 실무에서 계속 써왔는데 새롭게 정리하니 새롭다.
또한 WEB.XML 파일에 디스패처(서블릿,필터, 리스너) 설정을 했는데 이것은 스프링 부트로 오면서 자동화 되었다. 그렇게 돌아가는지 알았지만 이미 부트에서 자동화 되어 있었다. 거기다가 부트에서는 내장톰캣이 있어서 설정이 메이븐, 그래들 빌드도구 외에 application.yaml 파일로 간단하게 설정 한다.
이렇게 개발하면 개인프로젝트 할 때 참으로 편리하고 간편했다.
스프링 AOP도 생각해보니 조인포인트가 코드가 동작하는 시점/지점이고 포인트컷으로 필터링하는 표현식을 쓰고, 어드바이스가 적용될 위치를 정하는데 before니 after니 around니 하는 이런것들이 advice였다. 한참 하다보니 그냥 용어와 코드가 상관관계가 연관지어 이해되어 참 좋은 것 같다.
<aop:config>
<aop:aspect id="loggingAspect" ref="loggingAspect">
<aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))"/>
<aop:before method="logBeforeMethod" pointcut-ref="serviceMethods"/>
</aop:aspect>
</aop:config>
뭐 이런식으로 xml 설정하는 것만 봐서 잘 몰랐지만
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBeforeMethod() {
System.out.println("Method execution started");
}
}
이렇게 코드로 보면 이해가 잘된다. advice 로 before가 들어가 있고 뒤에 pointcut 으로 execution 관련 식이 있는데 패키지 내의 모든 클래스의 모든 메서드를 대상으로 한다고 되어 있다.
이러한 @Aspect 애노테이션으로 AOP를 활용하면 애플리케이션의 비즈니스 로직과 횡단 관심사를 분리하여 코드의 모듈화와 재사용성을 높일 수 있어서 좋은 것이다. 로깅이나 트랜잭션 관리의 횡단 관심사에 주로 쓰였던 이유가 이해가 된다.
스프링 시큐리티는 인증/인가 자원 페이지 관련 설정을 해준다.
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll() // /public 경로는 인증 없이 접근 가능
.anyRequest().authenticated() // 나머지 경로는 인증 필요
.and()
.formLogin()
.loginPage("/login") // 커스텀 로그인 페이지
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
유저 관련 설정을 해준다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.stereotype.Service;
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository; // UserRepository는 사용자 정보를 DB에서 조회하는 리포지토리
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 데이터베이스에서 사용자 정보 조회
com.example.demo.model.User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return User.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRoles().toArray(new String[0]))
.build();
}
}
확실히 JPA는 User 관련 설정을 하기 편하게 되어 있다. WebSecurityConfigurerAdapter를 확장하여 보안 설정을 사용자 정의할 수 있고 UserDetailsService를 구현하여 사용자 정보를 로드하고 인증에 사용하며, PasswordEncoder를 사용하여 비밀번호를 안전하게 저장하고 검증한다.
별첨으로 RestTemplate에서 번번히 사용하는 ResponseEntity 로 RESTful 한 서비스와의 상호작용을 쉽게 할수 있게 하는 것은 별미다. http요청과 응답이 간편하게 수행할 수 있다.
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class ApiService {
@Autowired
private RestTemplate restTemplate;
public String postExample() {
String url = "https://jsonplaceholder.typicode.com/posts";
Post post = new Post(1, "Title", "Body");
ResponseEntity<String> response = restTemplate.postForEntity(url, post, String.class);
return response.getBody();
}
static class Post {
private int userId;
private String title;
private String body;
public Post(int userId, String title, String body) {
this.userId = userId;
this.title = title;
this.body = body;
}
// Getters and setters
}
}
'4차산업혁명의 일꾼 > Java&Spring웹개발과 서버 컴퓨터' 카테고리의 다른 글
java 파일 다운로드/ 엑셀및 pdf 그리고 소켓통신 그리고 JSON 복습 (0) | 2024.06.17 |
---|---|
javascript/jsp및 프론트 복습 (0) | 2024.06.17 |
컴퓨터를 운영하는 시스템 소프트웨어 운영체제 (2) | 2024.06.06 |
컴퓨터를 보호하고 정보를 지키자~! 컴퓨터 보안~! (2) | 2024.06.01 |
정보를 공유하고 교류하는 컴퓨팅 정보통신망~! (2) | 2024.05.31 |