Stream groupingBy

어떤 객체의 List가 있을 때, 객체의 특정 필드값을 기준으로 묶는 과정이 필요했다. 그 때, stream의 groupingBy 을 사용하면된다. 예를들어, 블로그 포스트를 타입별로 묶고싶은 경우 아래 예시를 보면된다. class BlogPost { String title; String author; BlogPostType type; int likes; } enum BlogPostType { NEWS, REVIEW, GUIDE } Map<BlogPostType, List<BlogPost>> postsPerType = posts.stream() .collect(groupingBy(BlogPost::getType)); 참고 자료 https://www.baeldung.com/java-groupingby-collector

2024-09-15 · 1 min · 55 words

state, props

state와 props 둘 다 react의 구성요소인 컴포넌트를 렌더링하기 위한 정보를 담고 있다. state는 컴포넌트 안에서 관리되는 반면, props는 컴포넌트에게 정보를 전달하는 용도로 사용한다. setState() setState() 함수를 이용해서 state의 값을 변경하면 컴포넌트가 리렌더링된다. setState() 함수는 비동기로 처리되기때문에, 이 함수를 호출했다고 바로 state가 변경될거라고 생각하면 안된다. state의 이전값을 기준으로 값을 변경하고 싶다면 아래와 같이 함수를 전달하는 방식으로 구현해야된다. this.setState((state) => { // 중요: 값을 업데이트할 때 `this.state` 대신 `state` 값을 읽어옵니다. return {count: state....

2024-09-15 · 1 min · 78 words

SSH 접근을 위한 public private key 생성하기

ssh-keygen 이라는 명령어를 통해서 생성할 수 있다. ssh-keygen 위와 같이 아무를 옵션없이 키 쌍을 생성하면, ~/.ssh/id_rsa.pub 라는 파일에 생성된다. -t 옵셩능 사용하여 알고리즘과 크의 크기를 지정할 수도 있다. ssh-keygen -t rsa -b 4096 해당 키를 사용할 서버의 ~/.ssh/authorized_keys에 퍼블릭 키를 추가하면 된다. 참고 자료 https://m.blog.naver.com/sehyunfa/221737099486

2024-09-15 · 1 min · 45 words

Squash Merge 문제점

git squash는 conflict가 발생할 확률이 높다. sqaush merge로 병합을 해도 실제로는 병합이 아닌 새로운 커밋으로 만들어지기 때문에 merge한 브랜치와 conflict가 발생한다. https://stackoverflow.com/questions/11797904/git-merge-squash-and-recurring-conflicts

2024-09-15 · 1 min · 22 words

Sqrt Decomposition

문제 상황 처음에 segment tree를 이용해, 배열에 공통적인 변화량을 기록했다. 하지만, 이후에 주어진 범위 내에서 최대 값을 구해야되는 문제가 나왔다. 범위 내의 최대값을 구하기 위해서는 결국 segment tree의 모든 leef node를 탐색해야되므로 O(n)이 걸린다. 해결 방법 배열을 n개의 그룹으로 나누어서 공통적인 변화량을 기록한다. 배열의 크기는 n^(0.5)가 된다. 이렇게 하면 값을 수정할 때도 O(n^(0.5)) 가 걸리고, 최대값을 구할 때도 O(n^(0.5))의 시간 복잡도로 탐색을 하게된다. 참고 자료 https://kesakiyo.tistory.com/22

2024-09-15 · 1 min · 66 words

SQL에서 JOIN ~ ON과 WHERE 의 실행 순서

SQL문을 실행하면 일반적으로 아래와 같은 순서로 진행된다고 일고 있을 것이다. 1. FROM 2. ON 3. JOIN 4. WHERE 5. GROUP BY 6. WITH CUBE or WITH ROLLUP 7. HAVING 8. SELECT 9. DISTINCT 10. ORDER BY 11. TOP 하지만 이것은 논리적 처리 순서이다. SQL 문을 실행시키면 쿼리 옵티마이저가 인덱스를 사용할 수 있도록 JOIN과 WHERE의 순서를 바꿔서 처리한다. 실제 처리 순서와 논리적 순서가 다르다는 것을 이해할 필요가 있다. SELECT programmer.exercise, count(1) as count FROM hospital INNER JOIN covid ON covid....

2024-09-15 · 1 min · 128 words

SQL 튜닝 전에 알아야 될 용어

MySQL 구조 MySQL의 SQL 튜닝을 하기 전에 MySQL가 어떤 구조로 동작하는지 알 필요가 있다. MySQL Connectors를 통해 SQL문을 보내게되면 간략히 아래와 같은 과정을 거친다. Parser를 통해 MySQL 엔진에서 문법 에러가 있는지, DB에 존재하는 테이블을 대상으로 SQL문을 작성했는지 검사한다. Optimizer를 통해 요청한 데이터를 빠르고 효율적으로 찾아가는 전략적 계획을 만든다. 계획을 토대로 스토리지 엔진에 위치한 데이터를 찾는다. 찾은 데이터에서 불필요한 부분을 필터링하고 필요한 연산을 수행한 뒤에 사용자에게 반환한다. 스토리지 엔진 InnoDB, MyISAM, Memory 등과 같은 스토리지 엔진은 사용자가 요청한 SQL 문을 토대로 DB에 저장된 디스크나 메모리에서 필요한 데이터를 가져오는 역할을 한다....

2024-09-15 · 6 min · 1082 words

SQL 첫걸음

데이터베이스와 SQL 데이터베이스 데이터베이스: 데이터란 컴퓨터 안에 기록되어 있는 숫자를 의미하며, 이러한 데이터의 집합을 데이터베이스라고한다. 데이터베이스는 일반적으로 데이터센터의 서버에서 운용하지만 개인용 컴퓨터나 휴대용 기기에 내장되어 있기도 하다. 데이터베이스를 효율적으로 관리하는 소프트웨어를 데이터베이스 관리 시스템, 약자로 DBMS라 부른다. DBMS의 사용 목적은 다음과 같다. 생산성: 시스템을 구축할 때 검색, 추가, 삭제, 갱신과 같은 기본 기능부터 구현할 필요가 없어진다. 기능성: DBMS는 데이터베이스를 다루는 기능을 많이 제공한다. 복수 유저의 요청에 대응하거나, 대용량의 데이터를 저장하고 고속으로 검색하는 기능을 제공하기도 한다....

2024-09-15 · 13 min · 2648 words

Spring의 Thread pool

목표 Thread pool의 사용 목적을 이해한다. Spring boot에서 Tomcat의 Thread pool 설정 방법을 이해한다. Thread Pool DB, 웹 서버 등의 프로그램에서 요청이 도착할 떄마다 새 스레드를 생성하는 방법은 문제점이 있다. 요청을 처리할 때마다 스레드를 생성하고 삭제하는 것은 많은 시간과 시스템 리소스를 사용한다. 너무 많은 요청이 오면, 동시에 너무 많은 스레드가 생성되어 시스템 리소스가 부족해질 수 있다. 스레드 수를 제한할 필요가 있다. 이 문제를 해결하기 위해서 이전에 미리 생성된 스레드를 재사용하기 위한 Thread pool을 사용한다....

2024-09-15 · 2 min · 241 words

Spring으로 WebSocket 시작하기

Spring으로 WebSocket 시작하기(STOMP) Maven 의존성 추가 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>5.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>5.2.2.RELEASE</version> </dependency> 최신 버전은 여기서 또한 JSON 사용하여 메시지를 전달 하려면 Jackson 의존을 추가해야된다. Spring Boot의 경우에는 추가할 필요 없을 것으루 추정된다. <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.10.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.2</version> </dependency> Spring에서 WebSocket 활성화 AbstractWebSocketMessageBrokerConfigurer 클래스를 상속하고 @EnableWebSocketMessageBroker 어노테이션을 붙여준다. @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config....

2024-09-15 · 3 min · 476 words

Spring에서 Redis를 이용해 캐싱 구현하는 법

Spring에서 Redis 서버로 캐싱하는 방법은 2가지 방법이 있다. 기본적인 동작 확인만 목표로 하기 때문에 자세한 설정 방법은 생략한다. 어노테이션을 사용하는 방법 의존성 추가 implementation 'org.springframework.boot:spring-boot-starter-data-redis' Config에 @EnableCaching 추가 @SpringBootApplication @EnableCaching public class Application { ... } Entity에 Serializable 구현 Redis에서 데이터를 바이트 스트림으로 저장하기 위해서 필요하다. @Entity public class User implements Serializable{ @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; private String email; private Integer age; public User() { super(); } public User(Integer id, String name, String email, Integer age) { super(); this....

2024-09-15 · 2 min · 261 words

SpringApplicationEvent

목표 SpringApplicationEvent 가 무엇인지 알아본다. SpringApplicationEvent 의 사용법을 알아본다. SpringApplication.run() @SpringBootApplication public class AccountCoreApplication { public static void main(String[] args) { SpringApplication.run(AccountCoreApplication.class, args); } } Spring Boot를 사용하면 main 메서드에 다음과 같은 함수를 호출하는 것을 볼 수 있다. run 메서드를 호출하면 SpringApplication 생성자를 호출하는 것을 확인할 수 있다. SpringApplication 생성자를 호출하면 ApplicationListener를 로드하여 등록하게 된다. ApplicationListener 관심이 있는 이벤트에 대한 ApplicationListener를 ApplicationContext에 등록하면 ApplicationEvent가 그에 따라 필터링되고, 일치하는 이벤트에 대해서만 Listener가 호출이 된다....

2024-09-15 · 1 min · 149 words

Spring 이벤트 처리

도메인 간의 복잡한 의존성을 제거하기 위해서 Spring의 이벤트를 이용할 수 있다. 이벤트를 사용하기 위해서는 3가지를 사용해야된다. 참고로, Spring Framework 4.2부터 지원하는 어노테이션 방법을 다룬다. 이벤트 클래스 이벤트 퍼블리셔 이벤트 리스너 이벤트 클래스 이벤트에 데이터를 저장하기 위한 클래스로 자유롭게 클래스를 선언하면 된다. public class MenuRegisteredEvent { private final Menu menu; public MenuRegisteredEvent(final Menu menu) { this.menu = menu; } public Menu getMenu() { return menu; } public Long getMenuGroupId() { return menu....

2024-09-15 · 2 min · 236 words

Spring 실행 시 포트 번호 지정 방법

java -jar -Dserver.port=8083 spring-5.jar 또는 java -jar spring-5.jar --server.port=8083 참고 자료 https://recordsoflife.tistory.com/325

2024-09-15 · 1 min · 12 words

Spring with AWS S3

다른 크루들의 이야기를 들어보니 Spring과 S3 연결이 access key 가 없어도 된다고해서 시도해보고 있다. Spring 애플리케이션이 AWS의 EC2에 부여한 IAM 권한을 이용해서 S3와 연결이 가능하다고 한다. 의존성 추가 이것 저것 찾아다니면서 의존성 추가를 시도해봤는데 테스트가 전부 터지거나 의존성 추가에 실패했다. Spring 공식문서 방시대로 하니 다행이 잘 동작했다. implementation 'org.springframework.cloud:spring-cloud-aws-context:2.2.6.RELEASE' 접근 권한 AWS 자원들에 접근 권한을 얻기 위해서는 아래의 과정을 순서대로 거쳐서 만족하면 된다. 5번의 경우가 내가 사용하려고 하는 접근 권한 얻는 방법이다....

2024-09-15 · 1 min · 172 words

Spring Validation과 lombok 예외 처리

티 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 이 발생한다. 하지만 예외 메시지가 직접 담기는 것이 아니라 아래 코드와 같이 메시지를 뽑아내야된다....

2024-09-15 · 1 min · 114 words

Spring Security 시작하기

목표 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를 제공한다....

2024-09-15 · 2 min · 321 words

Spring rest docs의 API 문서가 자동으로 덮어쓰기

build.gradle에 아래 코드를 추가하면 된다. asciidoctor.doFirst { delete file('src/main/resources/static/docs') }

2024-09-15 · 1 min · 10 words

Spring Rest 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....

2024-09-15 · 2 min · 245 words

Spring redis로 pub sub 구현하기

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....

2024-09-15 · 1 min · 126 words