소프트웨어의 구성요소들은 확장에는 열려있고 변경에는 닫혀있어야 한다, 즉 요구사항의 변경이나 추가가 발생해도 기존 구성요소는 수정이 일어나지 않아야 한다. 흔히 OOP 5원칙에서 OCP를 만족시키기 위해서 사용하는 기법은 클래스 상속과 객체 합성을 통한 코드 재사용이라고 말한다. 상속이 어떤 문제가 있길래그러면 상속은 언제 사용해야 되나요? 먼저 상속을 사용하면, 자식클래스에 부모클래스를 덧붙이는 것으로 부모의 정의를 물려받은 후 코드를 추가하고 확장할 수 있다는 장점이 있다. 하지만 상속을 이용해서 코드를 재사용하기 위해서는 자식 클래스에서 부모 클래스의 구현법에 대한 지식을 가져야 하고, 그것은 부모 객체의 캡슐화를 약화시키는 문제를 가져오고, 결국 기능을 추가하는데 기존 구성요소를 수정하게 되..
예전에 풀었던, dp 메모이제이션을 이용하는 bfs/dfs문제인 ACM craft(https://eckrin.tistory.com/entry/BOJ-1005-ACM-Craft?category=985109)들과 유사한 문제다. 이런 유형의 문제를 한두번 푸는것이 아닌데도 계속 헷갈리는 이유는, dp를 사용했다고 해서 메모이제이션을 사용하는 것이 아니라는 사실을 자꾸 망각해서 그렇다. 뭔 소리나면, Queue queue = new LinkedList(); queue.add(new Location(0,0)); while(!queue.isEmpty()) { Location removeLoc = queue.remove(); int x = removeLoc.x; int y = removeLoc.y; int valu..
세션+쿠키 로그인 일반적으로 웹에서 서버로 url을 통해 요청하면, 서버에서는 적절한 컨트롤러가 매핑하고 내부 로직등을 통과한 후 뷰(html 등)를 리턴해준다. 이 때 (세션 만료 후)최초 요청시 헤더 쿠키를 이용하여 세션 id를 발급한 후 사용자 정보도 같이 저장하고, 이후 요청마다 서버의 세션 저장소에서 쿠키의 세션id를 확인하여 자동으로 사용자 인증과 함께 세션 만료 여부도 확인한다. (https://eckrin.tistory.com/entry/Spring-MVC-%EC%BF%A0%ED%82%A4%EC%84%B8%EC%85%98%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8) JWT? 그렇다면 왜 세션 로그인 방식이 아닌, Js..
UserDetails 스프링 시큐리티에서 사용자의 정보를 담는 인터페이스이다. 하지만 대부분의 경우 기본 UserDetails 인터페이스로는 구현에 한계가 있기 때문에 다음과 같이 UserDetails를 구현하여 사용한다. 스프링 시큐리티는 로그인 요청을 가로채서 인가처리를 하는데, 기존 UserDetails 대신 그것을 구현한 객체를 저장,관리하게끔 하자. UserDetails를 구현한 객체(PrincipalDetails)를 만들고, UserDetailsService를 구현한 객체(PrincipalDetailsService)에서 그것을 저장하면 시큐리티가 커스텀한 UserDetails를 사용하여 관리해주는 것 같다. //스프링 시큐리티가 로그인 요청을 가로채서 UserDetails를 구현한 객체를 저장..
이전 글 : https://eckrin.tistory.com/entry/Spring-MVC-%EC%BF%A0%ED%82%A4-%EC%84%B8%EC%85%98 쿠키를 사용해서 로그인을 할 수 있지만, 쿠키 값은 클라이언트가 임의로 변경 가능하다. 또한 쿠키에 저장된 정보도 가져가서 보관할 수 있기 때문에, 보안상의 문제가 있다. (클라이언트쪽에 보관되는 것들은 무조건 보안에 위험이 있다.) 따라서 사용자별로 예측 불가한 임의의 토큰을 노출해서 클라이언트 쪽에서 해킹이 이루어져도 찾을 수 없게 만들고, 서버에서 토큰과 사용자 id를 매핑해서 인식한 후, 그 토큰을 서버에서 관리하게 하면 된다. 또한 토큰 자체의 만료시간을 설정해서 토큰을 악용하지 못하게 하자. 세션, 쿠키 활용 세션 기반 인증의 state..
로그인 api를 개발할 때, 쿠키(영속 쿠키, 세션 쿠키)를 이용하여 로그인 상태를 유지할 수 있다. @PostMapping("/login") public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) { if(bindingResult.hasErrors()) { return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember==null) { bindingResult.reject("loginFail", ..
자바에서 배열 혹은 컬렉션 인스턴스의 조회를 위해서 흔히 for문 또는 foreach(iter)문을 사용하면서 요소 하나씩을 꺼내서 조회하였다. 간단한 경우에는 크게 문제되지 않지만, block으로 관리되는 특성상 로직이 복잡해지면 코드가 복잡해지는 문제가 있다. 자바 api 문서를 보면 스트림은 'A sequence of elements supporting sequential and parallel aggregate operations'라고 나와있다. 즉 배열이나 컬렉션과 같이 데이터를 나란히 저장하는 자료구조에서 원하는 결과를 필터링해서 얻어낼 수 있는 방법이다. 스트림을 사용하기 위해서는 크게 생성-필터링의 가공을 거쳐 결과를 사용하게 된다. 1. 생성 배열과 컬렉션 등의 다양한 자료구조에서 스트림..
절차적 프로그래밍, 전통적인 설계 원리 객체지향 프로그래밍 이전에 프로시저를 이용한 절차적 프로그래밍(procedural programming)이라는 방법이 많이 사용되었다. 이것은 프로시저(=함수)를 이용하여 절차적으로 프로그래밍을 하는 것으로, 메인함수뿐 아니라 여러 절차(기능)을 함수로 만들어 진행시키는 방식을 이야기한다. 순서도를 생각하면 쉽다. 필요한 기능들을 함수로 만들어놓고, 함수를 통해서 흐름을 나타내는 설계방식 하에서도 여러가지 설계 원리가 많이 나타났다. 단순성(simplicitiy): 유지보수를 위해서 가장 중요한 특성, 소프트웨어 유지보수는 비용이 매우 많이 드는 작업이기 때문에, 유지보수를 위해서는 단순하고 이해하기 쉬운 설계가 중요하다.효율성(efficiency): 단순..
LCS(Longest Common Subsequence, 최장 공통 부분수열) 최장 공통 부분수열이란, 존재하는 두 문자열 사이에 공통으로 존재하는 부분수열 중에 가장 길이가 긴 부분수열을 의미한다. 즉, ACAYKP와 CAPCAK라는 두 문자열이 존재한다면, ACAK(ACAYKP, CAPCAK)가 두 문자열의 LCS가 된다. 부분수열이기 때문에 수열이 연속될 필요는 없다. 수열이 반드시 연속된 문자여야 할 경우 최장 공통 문자열(LCS, Longest Common Substring)이라고 한다. LCS의 풀이는, 먼저 비교 문자열들의 길이에 따라 2차원 배열을 생성한다. 문자열 A("ACAYKP")와 문자열 B("CAPCAK")를 비교하는 상황이라고 하자. LCS[i][j]의 값은 문자열 A의 i번째 ..
1. 처음 문제를 보니깐 dp로 풀면 될 것 같아서 먼저 dp로 풀어보았다. import java.io.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] input = br.readLine().split(" "); int N = Integer.parseInt(input[0]); int K = Integer.parseInt(input[1]); int[] arr = new int[100001]; //0~100000 for(int i=0; i=0; i--) arr[i..
JPA 양방향 매핑 사용시 순환참조 문제가 발생할 수 있다. 상단 코드에서 Board와 Reply 엔티티는 일대다 양방향 매핑을 사용하고 있으며, Reply가 연관관계의 주인이 되어 fk를 가진다. 얼핏 보면 큰 문제가 없어보이지만, 다음과 같은 코드를 작성하면 문제가 발생할 수 있다. @GetMapping("/test/board/{id}") public Board getBoard(@PathVariable int id) { return boardRepository.findById(id).get(); } 위 코드는 @PathVariable로 넘겨받은 id값을 바탕으로 레포지토리에서 Board객체를 찾아서 반환하는 코드이다. 여기서 jackson이라는 라이브러리가 Board객체의 getter를 사용하여 엔티..
스프링 시큐리티 많은 프로젝트들이 기본적인 회원 관리를 필요로 하고 있고, 그것을 위해서 보안에 관련된 다양한 처리가 필요하다. 스프링은 spring security라는 하위 프레임워크에서 인증(Authentication)과 인가(Authorization)에 관련된 다양한 기능을 제공하고 있다. 인증(Authentication): 접근하려는 유저에 대한 확인 절차 (login, join..) 인가(Authorization): 인증된 사용자에 대해서 권한을 관리하는 것 접근주체(Principal): 보호 대상에 접근하려는 유저 비밀번호(Credential): 대상에 접근하려는 유저의 비밀번호 스프링 시큐리티 동작 원리 스프링 시큐리티는 이러한 인증과 인가를 위하여 Principal(=username)과 C..