Spring 실행 시 포트 번호 지정 방법
java -jar -Dserver.port=8083 spring-5.jar 또는 java -jar spring-5.jar --server.port=8083 참고 자료 https://recordsoflife.tistory.com/325
java -jar -Dserver.port=8083 spring-5.jar 또는 java -jar spring-5.jar --server.port=8083 참고 자료 https://recordsoflife.tistory.com/325
다른 크루들의 이야기를 들어보니 Spring과 S3 연결이 access key 가 없어도 된다고해서 시도해보고 있다. Spring 애플리케이션이 AWS의 EC2에 부여한 IAM 권한을 이용해서 S3와 연결이 가능하다고 한다. 의존성 추가 이것 저것 찾아다니면서 의존성 추가를 시도해봤는데 테스트가 전부 터지거나 의존성 추가에 실패했다. Spring 공식문서 방시대로 하니 다행이 잘 동작했다. implementation 'org.springframework.cloud:spring-cloud-aws-context:2.2.6.RELEASE' 접근 권한 AWS 자원들에 접근 권한을 얻기 위해서는 아래의 과정을 순서대로 거쳐서 만족하면 된다. 5번의 경우가 내가 사용하려고 하는 접근 권한 얻는 방법이다....
티 spring validation의 @NotNull과 lombok의 @NonNull의 차이를 알아본다. @NotNull Spring MVC Spring boot에서 컨트롤러에 @Valid와 함께쓰면 검증을 하게된다. 만약 조건을 만족하지 못하면 MethodArgumentNotValidException 이 발생한다. 하지만 예외 메시지가 직접 담기는 것이 아니라 아래 코드와 같이 메시지를 뽑아내야된다. private List<ExceptionDto> extractErrorMessages(final MethodArgumentNotValidException exception) { return exception.getBindingResult() .getAllErrors() .stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .map(ExceptionDto::new) .collect(Collectors.toList()); } JPA JPA에서도 @NotNull을 사용할 수 있다. @Entity 클래스의 필드에 @NotNull이 있으면 동작을한다. 만약 조건을 만족하지 않으면 ConstraintViolationException 이 발생한다. 하지만 예외 메시지가 직접 담기는 것이 아니라 아래 코드와 같이 메시지를 뽑아내야된다....
목표 Spring Security 내부 구조를 이해한다. Spring Security 사용 방법을 이해한다. Filters Filter와 FilterChain 클라이언트가 요청을 보내면, 서블릿 컨테이너에서 lazy하게 FilterChain를 생성한다. FilterChain은 Filter 인스턴스들과 하나의 Servlet을 포함한다. Spring MVC를 사용 중이라면 Servlet은 DispatcherServlet이 된다. Filter는 HttpServletRequest, HttpServletResponse를 수정한다. Filter는 호출될 때 FilterChain을 파라미터로 함께 받아서 다음 Filter를 연쇄적으로 호출한다. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { // do something before the rest of the application chain.doFilter(request, response); // invoke the rest of the application // do something after the rest of the application } DelegatingFilterProxy와 FilterChianProxy Spring은 Filter의 구현체인 DelegatingFilterProxy를 제공한다....
build.gradle에 아래 코드를 추가하면 된다. asciidoctor.doFirst { delete file('src/main/resources/static/docs') }
의존성 추가 <dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <version>2.0.4.RELEASE</version> </dependency> Spring REST Docs는 문서화할 REST 서비스의 테스트를 처리해야 문서가 생성된다. 테스트를 실행하면 request와 response를 통해 문서 스니펫이 생성된다. @ExtendWith({RestDocumentationExtension.class, SpringExtension.class}) @SpringBootTest public class ApiDocumentationJUnit5IntegrationTest { //... } @BeforeEach public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) { this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) .apply(documentationConfiguration(restDocumentation)).build(); } 컨트롤러(CRUDController)의 엔드 포인트에 대한 링크가 있는 페이지를 반환하는 컨트롤러 생성 @RestController @RequestMapping("/") public class IndexController { static class CustomRepresentationModel extends RepresentationModel<CustomRepresentationModel> { public CustomRepresentationModel(Link initialLink) { super(initialLink); } } @GetMapping public CustomRepresentationModel index() { return new CustomRepresentationModel(linkTo(CRUDController....
Redis 의존 추가 implementation 'org.springframework.boot:spring-boot-starter-data-redis' spring-boot-starter-data-redis 의존을 통해 properties 파일로 설정이 가능하다. Bean 생성 @Bean public RedisTemplate<String, Object> redisTemplate(final RedisConnectionFactory connectionFactory) { final RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); return template; } pubish 하기위한 RedisTemplate다. @Bean RedisMessageListenerContainer redisContainer(final MessageListener messageListener) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(jedisConnectionFactory()); container.addMessageListener(messageListener, topic()); return container; } 메시지 수신에 대한 비동기 처리를 하기위해서는 RedisMessageListenerContainer 에 MessageListener를 추가하면 된다. @Override public void onMessage(final Message message, final byte[] pattern) { try { EntryResponse response = objectMapper....
의존 추가 Spring에서 RSS 지원은 ROME이라는 프레임워크를 기반으로 한다. <dependency> <groupId>com.rometools</groupId> <artifactId>rome</artifactId> <version>1.10.0</version> </dependency> 피드 구현 AbstractRssFeedView 를 구현해야된다. 2가지 메서드를 오버라이드해야된다. buildFeedMetadata는 해당 피드에 대한 정보를 반환하고, buildFeedItems는 피드에 있는 아이템들을 반환한다. public class PostRssView extends AbstractRssFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Channel feed, HttpServletRequest request) { feed.setTitle("Baeldung RSS Feed"); feed.setDescription("Learn how to program in Java"); feed.setLink("http://www.baeldung.com"); } @Override protected List<Item> buildFeedItems(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) { Item entryOne = new Item(); entryOne....
스프링 @MVC 스프링은 DispatcherServlet과 7가지 전략을 기반으로 한 MVC 프레임워크를 제공한다. 애노테이션을 중심으로 한 새로운 MVC의 확장 기능은 @MVC라는 별칭으로도 불린다. 스프링 웹 기술과 스프링 MVC 엔터프라이즈 애플리케이션의 가장 앞단에서 클라이언트 시스템과 연동하는 책임을 맡고 있는 것이 웹 프레젠테이션 계층이다. Java의 웹 프레젠테이션 계층의 기술과 프레임워크는 매우 다양하여 선택의 폭이 넓다. 스프링은 기본적으로 웹 계층과 다른 계층을 깔끔하게 분리해서 스프링 애플리케이션이지만 웹 계층을 다른 기술로 대체하더라도 아무런 문제가 없게 만들 수 있다....
이전에 사용했던 @Where 어노테이션과 @SQLDelete 어노테이션을 사용하면 된다. @Entity @Table(name = "table_product") @SQLDelete(sql = "UPDATE table_product SET deleted = true WHERE id=?") @Where(clause = "deleted=false") public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private double price; private boolean deleted = Boolean.FALSE; // setter getter method } @SQLDelete 도 실제로 DB에 쿼리를 보낼 때 적용하게 되므로, 영속성 컨텍스트에 남아 있는 엔티티는 findAll() 같은 메서드로 조회가 되니 유의해야 된다....
이 글은 Spring Framework에서 멀티 모듈을 적용하면서 겪은 트러블 슈팅들을 정리한 글이다. 모듈 및 패키지 구조 크게 api, client, core라는 모듈로 나뉘어지고, api와 client는 core 모듈의 의존한 상태다. 이후 소개할 트러블 슈팅들은 api와 core 사이의 관계로 설명하겠다. api 모듈과 core 모듈은 아래의 디렉터리 구조를 가지고 있다. 아래는 main 메서드가 있는 클래스의 코드다. @SpringBootApplication public class HyNoticeApplication { public static void main(String[] args) { SpringApplication.run(HyNoticeApplication.class); } } 트러블 슈팅 Parameter 0 of constructor in hynotice....
동작방식을 이해하기 위해서 JpaRepository의 기본 구현체를 확인해볼 필요가 있었다. 기본 구현체인 SimpleJpaRepository 코드를 확인해보니, class 레벨에 @Transactional(readOnly = true)가 설정되어 있고, 쓰기 메서드에 각각 @Transactional이 명시되어 있었다. 따라서, 기본적으로 각 메서드 호출마다 영속성 컨텍스트가 별개로 만들어져서 엔티티가 관리된다. 참고 자료 https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/support/SimpleJpaRepository.html https://www.baeldung.com/jpa-hibernate-persistence-context
배경 config 클래스 중에 Condition 인터페이스의 구현체가 있었는데, 어떤 용도인지 이해하지 못했다. Custom Conditions 정의 조건부로 빈을 등록할 때 @Conditional 애노테이션을 사용할 수 있다. 이 애노테이션에서 사용할 조건을 클래스로 만들 수 있다. class Java8Condition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return JavaVersion.getJavaVersion().equals(JavaVersion.EIGHT); } } 사용 예 @Service @Conditional(Java8Condition.class) public class Java8DependedService { // ... } 참고 자료 https://www.baeldung.com/spring-conditional-annotations
Spring boot의 경우 ResourceHttpRequestHandler 라는 정적 리소스를 처리하는 핸들러가 따로있다. 기본적으로 /static, /public, /resources, /META-INF/resources 디렉토리에 있는 정적 컨텐츠를 처리하고 있다. https://www.baeldung.com/spring-mvc-static-resources https://github.com/spring-projects/spring-framework/blob/main/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
목표 TestContainers를 통해 개발 환경에서 Spring 애플리케이션 실행 시 mariaDB 컨테이너를 실행하도록 한다. TestContainers를 통해 이미 mariaDB 컨테이너가 실행 중이라면 재사용하도록 한다. 의존성 추가 일반적으로 TestContainers는 테스트 환경에 사용하지만, Spring 애플리케이션이 dev 프로파일로 실행될 때 사용하는 것이 목표여서 아래와 같이 의존성을 추가한다. mariaDB를 사용하기 위한 JDBC Driver도 함께 의존성 추가한다. dependencies { //... implementation("org.mariadb.jdbc:mariadb-java-client") implementation("org.springframework.boot:spring-boot-testcontainers") implementation("org.testcontainers:mariadb") //... } 컨테이너 자동 실행 Spring Boot 3.1부터 Container 클래스를 Bean 등록하면, 자동으로 컨테이너를 실행해준다....
배경 Spring Boot에서 @NotBlank를 사용했는데 존재하지 않는 애노테이션으로 인식했다. Spring Boot의 웹 스타터에 validation api를 구현한 하이버네이트 컴포넌트가 존재한다고 알고 있었는데, 의문이었다. 원인 및 해결 Spring Boot 2.3 부터 웹 스타터에서 validation 스타터가 분리되었다. 아래와 같이 직접 의존을 추가해줘야 된다. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> dependencies { ... implementation 'org.springframework.boot:spring-boot-starter-validation' } 참고 자료 https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes#validation-starter-no-longer-included-in-web-starters https://stackoverflow.com/questions/48614773/spring-boot-validation-annotations-valid-and-notblank-not-working
목표 Spring Batch의 구조를 이해한다. Spring Batch 사용법을 이해한다. Spring Batch 구조 스프링 배치는 Application, Batch Core, Batch Infrastructure 3가지 컴포넌트를 가진다. Application: 개발자가 작성하는 모든 배치 job과 사용자 정의 코드가 있다. Batch Core: 배치 작업을 시작하고 제어하는 데 필요한 핵심 런타임 클래스가 포함되어 있다. JobLauncher, Job, Step 구현체가 존재한다. Batch Infratstructure: 애플리케이션 개발자와 배치 코어에서 사용하는 클래스들이 포함되어 있다. ItemReader, ItemWriter RetryTemplate 하나의 Job에는 여러 개의 Step이 있고, Step에는 ItemReader, ItemProcessor, ItemWriter를 하나씩 가지고 있다....
목표 AOP가 무엇인지 이해한다. Spring AOP를 사용하는 방법을 이해한다. Spring AOP의 내부 구조를 이해한다. AOP(Aspect-Oriented Programming) Cross-Cutting Concern concern: 기능에 따라 분리한 시스템의 동작 concern의 2가지 종류 core concern: 주요 요구사항에 대한 기능 cross-cutting concern: 보조되는 또는 시스템 전반적인 요구 사항 예시: 로깅, 보안, 데이터 전송 등 aspect: cross-cutting concern을 모듈화한 것 AOP cross-cutting concern을 분리하여 모듈성을 높이는 것을 목표로하는 프로그래밍 패러다임 새로운 동작이 필요하면, 기존 코드에 추가하지 않고 분리된 새로운 코드를 선언할 수 있다....
sort() 함수의 key 파라미터를 통해서 정렬 기준을 변경할 수 있다. 이 파라미터는 람다를 파라미터로 받는다. 람다는 요소를 파라미터로 받고, 우선 순위가 높은 정렬 기준을 앞으로 오도록 하는 튜플을 반환하면 된다. 역순으로 정렬하고 싶다면 -x[0] 와 같이 두면 역순으로 정렬된다. temp.sort(key=lambda x : (x[0], x[1])) # '-'부호를 이용해서 역순으로 가능 좀 더 복잡한 비교 연산이 필요한 경우 함수를 사용해야된다. functools 모듈을 불러와서 functools.cmp_to_key() 의 파라미터로 자신이 커스텀한 함수를 주면 된다. 왼쪽의 값이 먼저 오고싶다면 -1을, 오른쪽 값이 먼저 오고싶다면 1을, 같다면 0을 반환하면된다....
socket.io란? WebSocket 등으로 양방향 통신을 가능하게 해주는 라이브러리다. 2가지 주요 기능으로 분류할 수 있다. Node.js 서버를 위한 라이브러리 클라이언트의 JavaScript 라이브러리 socket.io는 JavaScript뿐만아니라 Java, C++, Swift 등의 다양한 언어를 지원해준다. socket.io의 주요 기능 HTTP long-polling fallback: 브라우저가 WebSocket 연결에 실패할 경우 long polling 방식으로 통신을 하도록 만들어준다. Automatic reconnection: heartbeat 매커니즘으로 연결 상태를 확인하고, 연결이 끊겼을 때 자동으로 재연결한다. Broadcasting: 서버에서 연결되어 있는 모든 클라이언트에게 이벤드를 보낼 수 있다. 기본 API 3000번 포트를 사용하는 Node....