[Java]

  • JVM: 운영 체제의 메모리 영역에 접근하여 메모리를 관리하는 프로그램이다. 메모리 관리나 가비지 컬렉터를 수행한다
  • Garbage Collector: 동적으로 할당된 메모리 영역 중 사용하지 않는 영역을 방지하여 해제하는 기능이다.
    • Java에서 동적으로 할당된 메모리란? --> 힙 영역
      • Stack: 정적으로 할당한 메모리 영역으로, 원시 타입의 데이터가 값과 함께 할당된다. 힙 영역에 생성된 Object 타입의 데이터의 참조값 할당
      • Heap: 동적으로 할당한 메모리 영역으로, 모든 Object 타입의 데이터가 할당된다. 힙 영역의 Object를 가리키는 참조 변수가 스택 영역에 저장된다. 힙 영역은 New Generation 영역과 Old Generation 영역으로 이루어져 있다.
        • New generation:
          • Eden: 새로운 객체는 Eden 영역에 할당된다. Eden영역이 모두 사용되면 GC가 발생하는데, 이때 일어나는 가비지 컬렉터가 Minor GC라고 한다.
          • Servival 0: 이 이후에 살아남은 객체(Eden 영역의 Reachable 객체)를 Servival 0 영역으로 이동한다. Eden영역의 Unreachable 객체는 메모리에서 해제한다. Servival 0 영역이 다 차면 또 다시 Mark & Sweep 과정을 반복한다.
          • Servival 1: Servival 0 영역에서 살아남은 객체들을 Survival 1 영역으로 이동한다. 이동한 객체는 Age값 증가한다. 그 다음에 새로운 객체가 Eden 영역으로 들어와서 Minor GC가 발생하면 아까처럼 Servival 0 으로 가는 것이 아니라, 객체가 차 있는 곳으로 이동하기 때문에 바로 Servival 1 로 이동하게 된다. (즉, Servival 0/1중 둘 중 하나는 항상 비어있는 상태로 유지된다.) 만약 Servival 1 이 다 차면 Servival 1에 대해 Mark & Sweep 과정이 일어나고 Servival 0 으로 이동 + Age 1 증가하게 된다.
        • Old generation: Servival 영역의 Age 값이 증가하다가 특정 Age 값을 넘어서면, 그 때 Old generation으로 이동한다. 이 과정을 Promotion 과정이라고 한다. 만약 Old generation영역이 다 사용되면 Major GC가 발생한다.
        • --> 이 과정이 반복되면서 가비지 컬렉터가 메모리를 관리한다.
    • Garbage Collecter 과정(Mark & Sweep)
      • 가비지 컬렉터가 스택 영역의 모든 변수를 스캔하면서 각각 어떤 객체를 참조하고 있는지 찾아서 마킹한다.
      • Reachable Object가 참조하고 있는 객체도 찾아서 마킹한다.
      • 마킹되지 않은 객체를 힙 영역에서 제거한다.
  • 오버 로딩 vs 오버 라이딩
    • 오버로딩은 이름은 같지만 파라미터의 수와 타입, 또는 순서가 다른 메소드를 중복으로 선언하는 것이다. 이 때 리턴 타입이나 접근 제어자(private, public)은 관계 없음, 오버로딩은 메소드 오버로딩 또는 생성자 오버로딩이 있을 수 있다.
    • 오버라이딩은 상속의 개념으로 상위 클래스가 가지고 있는 메서드를 하위 클래스가 재 정의하여 하위 클래스의 메서드를 우선적을 사용하는 것이다. 
  • 인터페이스
    • 모든 메서드가 구현부 없는 추상 메서드로 이루어진 클래스
    • 인터페이스를 사용하는 이유는 개발코드와 객체가 서로 통신하는 접점 역할. 개발 코드에선 객체의 내부 구조를 모르더라도 인터페이스의 메서드 명만 알고 있으면 되기 때문에 객체가 수정될 경우에 개발 코드 부분을 수정하지 않을 수 있다.
  • JDBC
    • Java에서 데이터베이스에 접속할 수 있도록 하는 자바 API.
    • 데이터베이스에서 자료를 쿼리하거나 업데이트 하는 방법을 제공한다.

 

[Spring/Spring boot]

  • spring과 spring boot의 차이점
    • spring framework를 이용해서 엔터프라이즈 애플리케이션을 보다 쉽게 만들 수 있다. 스프링의 가장 중요한 특징은 DI와 IOC인데, 이를 통해 객체간의 결합도를 느슨하게 만들어 줌으로써 단위 테스트를 용이하게 만들어준다. 또한 객체간 결합도가 낮아지면 코드의 재사용성도 올라간다. 이러한 것들에 의해 스프링 프레임워크를 이용하면 생산성이 올라간다. 엔터프라이즈 애플리케이션은 대규모 데이터 처리 및 트랜젝션 처리가 필요하다. 이러한 것들을 스프링 프레임워크가 제공해 주는 모듈을 이용하여 개발자는 비즈니스 로직에만 집중할 수 있다. --> 목표: 개발자들이 애플리케이션을 조금 더 쉽게 만들 수 있도록
    • 스프링 부트는 단독 실행되는, 상용화 가능한 수준의 스프링 기반 애플리케이션을 쉽게 만들어낼 수 있다. 최소한의 설정으로 스프링 플랫폼과 서드파티 라이브러리들을 사용할 수 있도록 하고 있다. --> 목표: 스프링 프레임 워크를 더 쉽게 사용할 수 있도록
    • 가장 큰 차이점은 dependency이다. 스프링은 dependency를 버전까지 정확하게 명시해 주어야 원하는 기능을 추가할 수 있지만, 스프링 부트는 조금 더 짧아졌고 버전 관리도 권장 버전으로 자동 설정된다. 특히 *starter* 의존성을 통해 알아서 의존성이 걸려 있는 것들을 기본적으로 넣어준다.  ex) spring-boot-starter-data-jpa, spring-boot-starter-security, spring-boot-starter-test, spring-boot-starter-web, spring-boot-starter-thymeleaf 등
      • io.spring.dependency-management: 스프링 부트의 의존성을 관리해주는 플러그인으로, dependency manager가 관리하는 프로젝트들은 알아서 호환성에 맞게 버전 관리를 해주며, 직접 버전을 명시하는 경우 해당 버전으로 오버라이딩 된다.
    • configuration의 경우 스프링은 어떤 처리를 할 것인지, 빈 등록 등 설정해줘야 할 것이 많지만 스프링 부트는 application.properties 또는 application.yml만 작성하면 된다.
    • spring boot
      • 간편한 Auto Configuration 설정 (스프링 기능을 위한 자동 설정 지원)
        • Spring boot는 @EnableAutoConfiguration 등의 어노테이션을 통해 스프링 프레임워크를 쓸 때 필요한 빈을 자동생성 한다. 이러한 빈들은 spring.factories에서 확인할 수 있다.
      • 편리한 의존성 관리 및 자동 권장 버전 관리
      • 내장 서버가 있어서 서버 구동 시간이 절반 가까이 단축된다.(디폴트는 톰캣인데 싫으면 configuration exclude tomcat하고 dependency jetty로 걸면 된다)
      • 내장 서블릿 컨테이너 덕분에 jar 파일로 간단하게 배포 가능하다. (내장 서버로 인한 간단한 배포 서버 구축)
        • 원래 스프링은 배포를 할 때 war 파일로 저장되는데, 이 것을 톰캣과 같은 was에 올려두고 배포를 하거나 시행해야 하는 번거로움이 있다. 
      • 스프링 security, data jpa 등의 다른 스프링 프레임 워크 요소를 쉽게 사용
  • Spring에서 경량 컨테이너를 사용하는 이유?
    • 스프링은 객체 지향을 기반으로 하는데, 객체 지향 프로그램은 낮은 결합도와 높은 갭슐화를 추구한다. 따라서 각 개체들의 결합도와 의존성을 낮추기 위해서 컨테이너를 사용한다.
  • Spring Triangle
    • IOC
      •  
    • AOP(Aspect Oriented Programming)
      • 객체지향 프로그래밍에서 기능별로 클래스를 분리했음에도 불구하고, 공통적으로 반복되는 중복 코드가 여전히 발생하는 단점을 해결하고자 나온 방식으로, 개발 코드에서는 비지니스 로직에 집중하고, 비즈니스 로직 앞/뒤에 공통 코드를 수행할 수 있게 함으로써 중복 코드를 줄일 수 있는 방식이다.
      • 이렇게 공통적인 부분을 분리하여 개발하고, 실행 시에는 조합/로깅/보안/트랜잭션 등 여러 모듈에서 공통적으로 사용하는 부분을 분리해서 관리할 수 있다. 코드를 더 단순하고 깔끔하게 작성 가능하다.
    • PSA(Portable Service Abstraction)
      •  
  • Spring 에서 빈 등록 방법은?
    • Spring에서 빈이란?
      • 스프링은 경량 컨테이너로서 객체 생성과 소멸 등 라이프 사이클을 관리하며 스프링 컨테이너로부터 필요한 객체를 얻을 수 있다. 스프링 IOC 컨테이너에 의해 인스턴스화/조립/관리되고, 애플리케이션의 핵심을 이루는 객체를 스프링 빈이라고 부른다. 빈과 빈 사이의 의존성은 컨테이너가 사용하는 메타데이터 환경설정에 반영된다.
    • 스프링 부트의 경우 @Component @Service @Controller @Repository @Bean @Configuration 등으로 필요한 빈들을 등록하고 필요한 곳에서 @Autowired를 통해 주입받아 사용하는 것이 일반적이다.
    • --> 의존성 주입을 하는 이유?
    • 의존성 주입이란 객체 내부에서 다른 객체를 직접 생성하지 않고, 외부에서 생성된 객체를 전달 받아 사용하는 방식으로, 인터페이스를 통해 객체를 넘겨 받음으로써 주입한 객체를 좀 더쉽게 대체할 수 있어 유지 보수가 편리해진다는 장점이 있다.
      • 방법 1: 클래스 선언부 위에 @Component 어노테이션을 사용하는 방법, @Service, @Controller, @Repository는 모두 @Component를 상속받고 있고, 해당 어노테이션으로 등록된 클래스들은 스프링 컨테이너에 의해 자동으로 생성되어 스프링 빈으로 등록된다. 
      • 방법2: 자바 설정클래스 이용하는 방법, @Configuration 어노테이션을 클래스 선언부 앞에 추가한다. 또한 특정 타입을 리턴하는 메서드를 만들고 @Bean 어노테이션을 붙여주면 자동으로 해당 타입의 빈 객체가 생성된다.
    • 스프링은 별도의 설정을 하지 않을 경우 한 개의 빈 객체만을 생성하며, 이들 빈 객체들이 '싱글톤' 범위를 갖는다고 표현한다. 
      • @Primary: @Bean 또는 @Component에 함께 사용하며 객체 생성의 우선권을 부여한다.
      • @Qualifier: @Autowired에 함께 사용하며 빈의 이름이 같은 객체를 찾는다.
      • 참고로 두 어노테이션을 동시에 쓸 경우 우선 순위는 @Qualifier, @Primary 순이다.
  • POJO 방식이란?
    • 구현을 위해 특정한 인터페이스를 구현하거나 상속받을 필요가 없어 기존에 존재하는 라이브러리를 지원하기 용이하고 객체가 가볍다.
  • Spring Security를 쓰는 이유(장점)?
    • 모든 url을 가로채어 인증을 요구
    • 로그인 폼을 생성해준다.
    • crsf공격을 막아준다. (crsf: cross-site request frogery 사이트간 요청 위조)
    • session fixation을 막아준다. (session fixation: 하나로 유효한 유저 세션을 탈취하여 인증을 우회하는 수법)
    • 요청 헤더 보안
    • servlet api 메소드 제공

 

 

[Database]

  • Transaction이란?
    • 데이터의 무결성으로 인하여 데이터 작업 시에 문제가 생기면 데이터 작업을 하기 이전 시점으로 모든 데이터를 원상 복구하는 것을 말한다. 즉, 모두 실행되거나 모두 실행되지 않거나를 뜻한다. 
    • 이전의 커밋(COMMIT)이 일어난 뒤부터 다음의 커밋(COMMIT) 전까지의 작업이 하나의 트랜잭션 이며, 커밋과 롤백(ROLLBACK)은 이러한 트랜잭션 단위로 데이터 베이스에서 발생한 작업을 저장, 삭제하는 일이다.
    • Commit : 작성한 쿼리문에서 Update, Delete, Insert를 수행했을 때, 그 쿼리문 수행결과에 대해 확정을 짓겠다는 뜻이다.
    • Rollback : 쿼리문 수행결과에 대해 번복을 함. 즉, 쿼리문 수행 이전으로 원상복귀 하겠다는 뜻이다 (Commit 하기 전에 사용 됨).
  • NoSQL이란?
    • NoSQL 데이터베이스는 관계형 데이터베이스(RDB)보다 덜 제한적인 일관성 모델을 이용하는 데이터의 저장 및 검색을 위한 매커니즘을 제공한다.
    • 단순 검색 및 추가 작업을 위한 매우 최적화된 키-값 저장 공간을 사용한다.
    • 빅데이터 시대에 따라 많은 양의 데이터를 효율적으로 처리하기 위해 등장하였다. (분산처리, 빠른쓰기 및 데이터의 안정성)
    • 분산형 구조를 통해 여러 대의 서버에 분산해 저장하고, 분산시에는 데이터를 상호 복제에 특정 서버에 장애가 발생했을 때에도 데이터 유실이나 서비스 중지가 없는 형태의 구조를 갖고 있다.
    • NoSQL이 기존 RDBMS와 다른 점은?
      • 스키마가 없다. 즉 데이터 관계와 정해진 규격(table-column의 정의)이 없다.
      • 관계 정의가 없으니 Join이 불가능하다. (하지만 reference와 같은 기능으로 비슷하게 구현은 가능.)
      • 트랜잭션을 지원하지 않는다.
      • 분산처리(수평적 확장)의 기능을 쉽게 제공한다.
      • 대부분의 NoSQL DB는 분산처리기능을 목적으로 나왔기 때문에 분산처리 기능을 자체 프레임워크에 포함하고 있다.
  • Index란?
    • 인덱스(Index)는 데이터를 논리적으로 정렬하여 검색과 정렬 작업의 속도를 높이기 위해 사용된다.
      예를 들면, 책에서 가장 빨리 내용을 찾는 방법은 책의 뒤편의 색인을 보는 것.
    • 기본키에 대해서는 항상 DBMS가 내부적으로 정렬된 목록을 관리하기에 특정 행을 가져올 때 빠르게 처리된다. 하지만, 다른 열의 내용을 검색하거나 정렬시에는 하나하나 대조를 해보기 때문에 시간이 오래걸린다. (이를 인덱스로 정의해두면 검색속도가 향상된다.)
    • 단점: 인덱스를 사용하면 데이터를 가져오는 작업의 성능은 향상시킬 수 있지만 데이터 삽입, 변경 등이 일어날 때 매번 인덱스가 변경되기 때문에 성능이 떨어질 수 있다.
    • 사용대상 : 데이터 필터링과 정렬에 사용되므로, 데이터를 특정한 순서로 자주 정렬한다면 인덱스를 사용하기에 적합
      • 데이터베이스는 내가 원하는 데이터를 어떻게 찾아오는 걸까?
      • 왜 데이터가 많아질수록 점점 느려질까?
      •  조인만 수행하면 느릴까?
      • 왜 쿼리가 느릴까?

[OS]

 

 

[디자인 패턴]

 

[네트워크]

  • 동기 방식과 비동기 방식의 차이점
    •  
  • tcp와 udp 차이점

 

 

  • spring bean/component annotation
  • spring boot 자동 구성 annotation
  • framework/library/api 차이
  • 웹 서버와 was 차이
  • 쿠키와 세션 차이
  • 캐시
  • restful이란
  • web에서 mvc 흐름에 대해 설명
  • 요청과 응답의 흐름 설명
  • http status와 method 설명
  • request와 response의 http header
  • 컬렉션 프레임 워크 list, map, set ckdl
  • hash function이란
  • JPA와 JDBC 차이
  • SQL 인젝션이란
  • 배포 용어 설명

Spring MVC 프레임워크 Support 추가 후 /web 패키지가 생성되는데, 이 아래에 있는 web.xml 파일의 아래 부분을

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.form</url-pattern>
  </servlet-mapping>

 

이렇게 바꿔줘야 한다.

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

 

톰캣의 web.xml파일은 톰캣의 실행환경에 대한 정보를 담당하는 환경설정 파일이다. 

각종 servlet의 설정과 servlet 매핑, 필터, 인코딩 등을 담당한다.
web.xml은 각 application이 deploy될 때 각 application의 'WEB-INF/web.xml' deployment descripter에 따라서 처리가 된다.


 

일단 서블릿과 웹 페이지 동작에 대해 잘 모르겠어서 관련 내용을 찾아 보았다.

 

서블릿이란 웹 프로그래밍에서 클라이언트의 요청을 처리하고 그 결과를 다시 클라이언트에게 전송하는 서블릿 클래스의 구현 규칙을 지킨 자바 프로그래밍 기술이다. 즉, 클라이언트의 HTTP 요청에 대해 특정 기능을 수행, HTML문서를 생성등의 응답을 하는 인터넷 서버 프로그램이다. 일반적으로 웹 서버는 정적인 페이지만을 제공한다. 따라서 동적인 페이지를 제공하기 위해서 웹 서버는 다른 곳에 도움을 요청하여 동적이 페이지를 작성해야 한다. 동적인 페이지로는 임의의 이미지만을 보여주는 페이지와 같이 사용자가 요청한 시점에 페이지를 생성해서 전달해 주는 것을 의미한다.

 

여기서 웹 서버가 동적인 페이지를 제공할 수 있도록 도와주는 어플리케이션이 서블릿이고, 동적인 페이지를 생성하는 어플리케이션이 Common Gateway Interface이다. CGI는 별도로 만들어 놓은 프로그램에 HTML의 GET/POST 방법으로 클라이언트의 데이터를 환경 변수로 전달하고, 프로그램의 표준 출력 결과를 클라이언트에게 전송한다.

 

서버와 클라이언트는 HTTP request/response로 통신하는데, 서버가 요청을 받으면 정적 자원에 대한 요청일 경우 자원을 반환해주고, 그렇지 않는 경우 CGI 프로그램을 실행하여 해당 결과를 리턴해준다. 이 때, 서버는 CGI 프로그램에게 클라이언트의 요청과 매개 변수를 전달해주고, 결과를 전달 받기 위한 파이프라인을 연결한다. 그래서 CGI 프로그램은 입력에 대한 서비스를 수행하고, 결과를 클라이언트에게 전달하기 위해 결과 페이지에 해당하는 MIME 타입의 컨텐츠 데이터를 웹 서버와 연결된 파이프라인에 출력하여 서버에 전달한다. 서버는 파이프라인을 통해 CGI 프로그램에서 출력한 결과 페이지의 데이터를 읽어 HTTP 응답헤더를 생성하여 데이터를 함께 반환해준다.

 

--> Servlet

  • 클라이언트의 요청에  대해 동적으로 작동하는 웹 어플리케이션 컴포넌트이다.
  • html을 사용하여 요청에 응답한다.
  • 자바 스레드를 이용하여 동작한다.
  • MVC 패턴에서 컨트롤러로 이용된다.
  • HTTP 프로토콜 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속받는다.
  • UDP보다 속도가 느리다.
  • HTML 변경 시 Servlet을 재컴파일 해야 하는 단점이 있다.

 

이 서블릿을 관리해주는 서블릿 컨테이너가 있다. 서블릿 컨테이너는 서블릿의 생명주기를 관리하고 요청에 따른 스레드를 생성해준다. 또, 클라이언트의 request를 받아주고 response를 보낼 수 있게 웹 서버와 소켓을 만들어 통신을 해준다. 서블릿 컨테이너의 예가 톰캣이다. 톰캣은 실제로 웹 서버와 통신하여 Java Server Page(JSP)와 Servlet이 작동하는 환경을 제공해준다.

 

--> Servlet Container이란

  • 웹 서버와의 통신 지원: 일반적으로 소켓을 만들어서 listen, accept를 함으로써 통신을 하지만, 서블릿 컨테이너는 서블릿과 웹 서버가 쉽게 통신할 수 있도록 API를 제공해준다. 
  • 서블릿 생명주기 관리: 서블릿 컨테이너는 서블릿 클래스를 로딩하여 인스턴스화 하고, 초기화 메소드를 호출하고, 요청이 들어오면 적절한 서블릿 메소드를 호출한다. 또한, 서블릿이 생명이 다 한 순간에는 적절하게 가비지 컬렉션을 진행한다.
  • 멀티 스레드 지원 및 관리: 서블릿 컨테이너는 요청이 들어올 때마다 새로운 자바 스레드를 하나 생성하는데, HTTP 메소드 실행 후에 스레드는 죽는다. 원래는 스레드를 관리해야 하지만 서버가 다중 스레드를 생성 및 운영해주기 때문에 스레드의 안정성에 대해서 걱정하지 않아도 된다.
  • 보안 관리: 서블릿 컨테이너를 사용하면 보안 관련 내용을 서블릿 또는 자바 클래스에 구현하지 않아도 된다. 일반적으로 보안 관리는 xml 서술자에 기록하기 때문에, 보안에  대해 수정할 일이 생기더라도 자바 소스 코드를 수정하여 다시 컴파일 하지 않아도 보안 관리가 가능하다. 

 


 

다시 web.xml 설정으로 돌아가서

톰캣의 ${TOMCAT_HOME}/conf/web.xml 파일에는 3개의 서블릿 매핑이 존재한다.

 

즉 *.jsp, *.jspx와 같은 url 패턴은 JspServlet이 처리하고,

DefaultServlet은 spring Controller mapping과 jsp 패턴에 걸리지 않는 요청 들을 처리한다.

(png, jpg, js, html등 정적인 content)

 

<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

...

<servlet-mapping>
	<servlet-name>jsp</servlet-name>
	<url-pattern>*.jsp</url-pattern>
</servlet-mapping>

...

<servlet-mapping>
	<servlet-name>jsp</servlet-name>
	<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

처음에 servlet-mapping을 /로 설정하면서 default 서블릿을 dispatcher 서블릿으로 덮어쓴 것이다.

그런데 이렇게만 해준다면 기존의 jsp 패턴에 걸리지 않던 png, jpg, js, html과 같은 정적인 content를 요청할 때 오류가 날 것이다.

 

.jsp든 .js, .css든 WAS만 구동하는경우 해당 파일에 직접접근하는 경우는 없다. 일단 요청은 톰캣이 모두 받게된다.

그리고 톰캣은 서블릿에 패턴을 통해서 요청을 처리하게되는데 /로 지정하게되면 *.jsp로 오는 요청은 jsp 서블릿이 처리하겠지만,

그 외에는 default 서블릿이 처리를 해야하는데 이 default 설정을 덮어써서 default 서블릿이 작동하지 않으면 문제가 발생한다.

 

이를 해결하기 위해서는 서블릿 필터 등을 통해 정적인 요청은 default 서블릿으로 명시적으로 위임하도록 하는 2가지 방법이 있다.

이 핸들러를 구성하면 dispatcher가 모든 요청을 default servlet으로 전달한다.

 

WebConfig.java

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
public class MvcConfiguration implements WebMvcConfigurer {

  @Bean
  public ViewResolver getViewResolver(){
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/");
    resolver.setSuffix(".html");
    return resolver;
  }

  @Override
  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
  }
}

 

servlet-context.xml: Default ServletHandler가 Bean으로 등록되며 동작

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  <mvc:annotation-driven/>
  <mvc:default-servlet-handler/>
</beans>

 

마지막으로 project structure - articats에 들어가서 필요한 라이브러리를 추가해주도록 한다.

- Spring_5_2_3_RELEASE

- Spring_MVC_5_2_3_RELEASE

 

참고

https://lng1982.tistory.com/97

https://multifrontgarden.tistory.com/145

 

- spring boot 2.3.2

- mysql 8.0.21 for osx10.15 on x86_64 (Homebrew)

- 데이터 저장 계층 jpa, hibernate

- 빌드 gradle

 

구현해 볼 기능을 쭉 정리해보면 크게 4가지이다.

  • 회원은 글/댓글/강의평가/시간표를 생성할 수 있다.
  • 글과 댓글에는 여러 종류의 사진을 선택하여 넣을 수 있다.
  • 시간표에는 여러 강의를 선택하여 넣을 수 있다.

연관 관계를 알아보면,

  • 회원-글/시간표/강평/댓글: 일대 다 관계
  • 글-댓글: 일대 다 관계
  • 글/댓글-사진: 일대 다 관계
  • 강의-강의평가: 일대 다 관계
  • 시간표-강의:다대 다 관계
    • 시간표에 다른 강의 여러개 넣을 수 있고
    • 같은 강의가 여러 시간표에 들어갈 수 있다
    • --> 다대 다 관계는 관계형 데이터베이스 뿐만 아니라 엔티티에서도 거의 사용하지 않는다고 함
    • --> 따라서 연결 엔티티 강의시간표를 추가해서 일대다 관계+다대일 관계로 만들도록 한다.
    • 강의 시간표에는 담은 강의의 학점 합도 포함하도록 한다.
  • 추가) 즐겨찾기의 경우도 다대다 관계이므로 관계를 쪼개도록 한다.

위 관계를 기반으로 엔티티의 관계를 그려보면

  • 회원 기능
    • 회원 등록
  • 게시판 기능
    • 글 등록
    • 글 조회
    • 댓글 등록
    • 공감/비공감
    • 즐겨찾기
  • 시간표 기능
    • 시간표 만들기
    • 시간표 조회
  • 강의평가 기능
    • 강의평가 등록
    • 강의평가 조회
    • 강의평가 검색

 

DB에 저장해야 할 정보 목록

  • User(회원)
    • id
    • user_id
    • user_pwd
    • email
    • name
    • nickname
    • is_verified
    • level
    • files
  • Board(글)
    • id
    • time
    • views
    • title
    • contents
    • user_id
    • upvote
    • downvote
  • Favorite(즐겨찾기)
    • user_id
    • board_id
  • Comments(댓글)
    • id
    • user_id
    • board_id
    • contents
    • upvote
    • downvote
  • Lecture(강의)
    • id
    • professor
    • lecture_name
    • lecture_numbers
    • semester
    • department
    • credit
  • Lecture_Evaluation(강의 평가)
    • id
    • lecture_id
    • professor
    • content
    • evaluate
    • evaluate_credit
    • evaluate_assignment
    • evaluate_teamproject
    • evaluate_attendance
    • evaluate_testlevel
    • evaluate_testcategory
  • Schedule(시간표)
    • id
    • user_id
    • lecture_id
    • credits

 

 

정규화 후 DB Schema

 

데이터베이스 정규화는 어디까지 진행해야하는지 잘 모르겠다...

정규화/반정규화는 모든 기본화면에 해당 항목이 함께 조회되어야 하느냐 아니냐에 따라 결정하면 된다고 하는데,

일단 사용자가 필요로 하는지, 그냥 시스템적으로만 필요한 것인지 나눠서 생각해보고

테이블 조인을 할지 아니면 한 테이블에 모두 저장을 할지 결정해야 할 것 같다.

 

일단은 아래와 같이 정규화 해 보았다. 하다가 바뀔수도 있음...

 

ER-Diagram

 

 

CREATE DATABASE ewhaianDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE ewhaianDB;

CREATE TABLE IF NOT EXISTS Users (
    id varchar(40) primary key,
    u_id varchar(40) not null,
    u_password varchar(40) not null,
    email varchar(40) not null,
    name varchar(20) not null,
    nickname varchar(20) not null,
    is_verified binary not null,
    level integer not null
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS UploadedFiles (
    id varchar(40) primary key,
    user_id varchar(40) not null,
    image_file blob not null,
    time datetime not null,
    foreign key(user_id) references Users(id)
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Board (
    id integer primary key,
    user_id varchar(40) not null,
    views integer default 0,
    title varchar(100) not null,
    content text not null,
    upvote integer default 0,
    downvote integer default 0,
    file_id varchar(40),      
    time DateTime not null,              
    foreign key(user_id) references Users(id),
    foreign key(file_id) references UploadedFiles(id)
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Comments (
    id integer primary key,
    user_id varchar(40) not null,
    board_id integer not null,
    depth integer default 0,
    contents text not null,
    upvote integer default 0,
    downvote integer default 0,
    file_id varchar(40),
    time datetime not null,
    foreign key(user_id) references Users(id),
    foreign key(board_id) references Board(id),
    foreign key(file_id) references UploadedFiles(id)
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Schedule_Time (
    id varchar(40) primary key,
    time varchar(20) not null
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Professors (
    id varchar(40) primary key,
    name varchar(30) not null
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Departments (
    id varchar(40) primary key,
    name varchar(30) not null
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Lectures (
    id varchar(40) primary key,
    department_id varchar(40) not null,
    name varchar(30) not null,
    credit float4 not null,
    lecture_code varchar(10),
    foreign key(department_id) references Departments(id)
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Lecture_Held (
    id varchar(40) primary key,
    lecture_id varchar(40) not null,
    lecture_division integer default 1,
    professor_id varchar(40) not null,
    semester varchar(10) not null,
    lecture_place varchar(40),
    lecture_time varchar(40),
    foreign key(lecture_id) references Lectures(id),
    foreign key(professor_id) references Professors(id),
    foreign key(lecture_time) references Schedule_Time(id)
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Schedule (
    id varchar(40) primary key,
    user_id varchar(40) not null,
    lecture_id varchar(40) not null,
    priority integer default 0,
    foreign key(user_id) references Users(id),
    foreign key(lecture_id) references Lecture_Held(id)
) CHARSET=utf8;

CREATE TABLE IF NOT EXISTS Lecture_Evaluation (
    id varchar(40) primary key,
    lecture_id varchar(40) not null,
    user_id varchar(40) not null,
    contents text not null,
    evaluate integer not null,
    evaluate_credit integer,
    evaluate_assignment integer,
    evaluate_teamproject integer,
    evaluate_attendance integer,
    evaluate_testlevel integer,
    evaluate_tests integer,
    time datetime not null,
    foreign key(lecture_id) references Lecture_Held(id),
    foreign key(user_id) references Users(id)
) CHARSET=utf8;

 

https://github.com/sypark9646/ewhaian-clone-project

 

sypark9646/ewhaian-clone-project

Contribute to sypark9646/ewhaian-clone-project development by creating an account on GitHub.

github.com

 

'프로젝트' 카테고리의 다른 글

항공 규정 번역 시스템  (0) 2020.07.11
Emotion Analyze Speaker  (0) 2020.07.10

"연속된" 파일을 합쳐서 하나의 파일로 만들 때 비용이 최소일 때를 구하는 문제이다.

 

DP[i][j] = i ~ j번 파일을 합치는 최소 비용이라고 할 때,

DP[i][j] = min(DP[i][k] + DP[k+1][j]) + (A[i] ~ A[j] 까지의 합) 일 것이고 시간 복잡도는 O(N^3)이다.

 

import java.util.*;
import java.io.*;

public class Main {
	public static void main(String[] args) throws NumberFormatException, IOException {
		Scanner in = new Scanner(System.in);
		int test = in.nextInt();
		for (int t = 0; t < test; t++) {
			int n = in.nextInt();
			int page[] = new int[n + 1];
			int pageSum[] = new int[n + 1];
			for (int i = 1; i <= n; i++) {
				page[i] = in.nextInt();
				pageSum[i] = pageSum[i - 1] + page[i];
			}
			int dp[][] = new int[n + 1][n + 1];
			for (int i = 1; i <= n; i++) {
				Arrays.fill(dp[i], -1);
			}
			System.out.println(DP(dp, pageSum, 1, n));
		}
	}

	public static int DP(int dp[][], int pageSum[], int i, int j) {
		if (i == j) {
			dp[i][j] = 0;
			return dp[i][j];
		}

		if (dp[i][j] != -1) {
			return dp[i][j];
		}

		for (int k = i; k < j; k++) {
			int temp = DP(dp, pageSum, i, k) + DP(dp, pageSum, k + 1, j) + pageSum[j] - pageSum[i - 1];
			if (dp[i][j] == -1 || dp[i][j] > temp) {
				dp[i][j] = temp;
			}
		}
		return dp[i][j];
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 10253: 헨리  (0) 2020.12.24
boj 1520: 내리막길  (0) 2020.12.15
boj 1509: 팰린드롬 분할  (0) 2020.07.21
boj 10942: 팰린드롬?  (0) 2020.07.20
boj 1890: 점프  (0) 2020.07.20

어떤 문자열을 팰린드롬으로 분할하는데, 분할 개수의 최솟값을 구하는 문제이다.

 

일단 팰린드롬의 연속이 되어야 하고,

정답의 최댓값은 N이 될 것이다. (길이가 1인 문자열은 항상 팰린드롬이니까)

 

DP[i]: str[i]까지 문자열까지의 팰린드롬 분할 갯수의 최솟값

DP[i] = Math.min(D[j-1]) + 1(단, j ~ i까지는 팰린드롬)

=> 시간복잡도는 DP를 채워야 하는 갯수 N * j를 찾는 시간 N * i~ j가 팰린드롬인지 아닌지 찾을 때 O(1): O(N^2)

 

import java.util.*;
import java.io.*;

public class Main {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringTokenizer st;

		String str = br.readLine();
		char[] arr = str.toCharArray();

		int n = str.length();
		int dp[][] = calcPalindrome(arr, n);
		int ans = calcDividedPalindrome(dp, n);
		bw.write(String.valueOf(ans));
		bw.flush();
		bw.close();
	}

	public static int[][] calcPalindrome(char arr[], int n) {
		int dp[][] = new int[n + 1][n + 1];

		// 길이가 1일 때
		for (int i = 1; i <= n; i++) {
			dp[i][i] = 1;
		}

		// 길이가 2일 때
		for (int i = 1; i <= n - 1; i++) {
			if (arr[i - 1] == arr[i]) {
				dp[i][i + 1] = 1;
			}
		}

		// 길이가 3 이상
		for (int i = 3; i <= n; i++) {
			for (int j = 1; j <= n - i + 1; j++) {
				int k = j + i - 1;
				if (arr[j - 1] == arr[k - 1] && dp[j + 1][k - 1] == 1) {
					dp[j][k] = 1;
				}
			}
		}

		return dp;
	}

	public static int calcDividedPalindrome(int dp[][], int n) {
		int maxDivided[] = new int[n + 1];

		for (int i = 1; i <= n; i++) {
			maxDivided[i] = -1;
			for (int j = 1; j <= i; j++) {
				if (dp[j][i] == 1) {
					if (maxDivided[i] == -1 || maxDivided[i] > maxDivided[j - 1] + 1) {
						maxDivided[i] = maxDivided[j - 1] + 1;
					}
				}
			}
		}

		return maxDivided[n];
	}
}

 

BufferedWriter is a method that flush the buffer and write the characters directly to the underlying stream.

따라서 int형의 ans를 바로 bw.write하게 되면 char형으로 output이 나온다.

따라서 String형으로 바꿔준 뒤 쓰도록 한다.

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1520: 내리막길  (0) 2020.12.15
boj 11066: 파일 합치기  (0) 2020.07.21
boj 10942: 팰린드롬?  (0) 2020.07.20
boj 1890: 점프  (0) 2020.07.20
boj 11660: 구간 합 구하기 5  (0) 2020.07.19

어떤 문자열이 팰린드롬인지 확인하는 2가지 방법 --> O(N)

  • s == reverse(s) 인지 확인
  • 모든 ch[i] == ch[s.length-i] 인지 확인

이 때, 쿼리의 갯수가 M개이므로 총 걸리는 시간은 O(MN)인데 시간 제한에 걸린다.

 

팰린드롬을 검사하는 다른 방법

  1. 길이가 1인 부분 수열은 반드시 팰린드롬 --> O(N)
  2. 길이가 2인 부분 수열은 두 수가 같을 때만 팰린드롬 --> O(N)
  3. 길이가 3이상인 경우는 DP를 이용한다.-->O(N^2)
    1. DP[i][j]: i ~ j까지 팰린드롬인지 아닌지 저장
    2. ch[i] == ch[j]이면 DP[i][j] = DP[i+1][j-1]이다.

=> O(N^2+M)만에 구할 수 있다.

 

public class Main {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringTokenizer st;

		int n = Integer.parseInt(br.readLine());
		int arr[] = new int[n + 1];
		st = new StringTokenizer(br.readLine());
		for (int i = 1; i <= n; i++) {
			arr[i] = Integer.parseInt(st.nextToken());
		}
		int dp[][] = new int[n + 1][n + 1];

		dp = calcPalindrome(arr, n);

		int m = Integer.parseInt(br.readLine());
		for (int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int start = Integer.parseInt(st.nextToken());
			int end = Integer.parseInt(st.nextToken());
			bw.write(dp[start][end] + "\n");
		}
		bw.flush();
		bw.close();
	}

	public static int[][] calcPalindrome(int arr[], int n) {
		int dp[][] = new int[n + 1][n + 1];

		// 길이가 1일 때
		for (int i = 1; i <= n; i++) {
			dp[i][i] = 1;
		}

		// 길이가 2일 때
		for (int i = 1; i <= n - 1; i++) {
			if (arr[i] == arr[i + 1]) {
				dp[i][i + 1] = 1;
			}
		}

		// 길이가 3 이상
		for (int i = 3; i <= n; i++) {
			for (int j = 1; j <= n - i + 1; j++) {
				int k = j + i - 1;
				if (arr[j] == arr[k] && dp[j + 1][k - 1] == 1) {
					dp[j][k] = 1;
				}
			}
		}

		return dp;
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 11066: 파일 합치기  (0) 2020.07.21
boj 1509: 팰린드롬 분할  (0) 2020.07.21
boj 1890: 점프  (0) 2020.07.20
boj 11660: 구간 합 구하기 5  (0) 2020.07.19
boj 1197: 최소 스패닝 트리  (0) 2020.07.19

(1, 1) -> (n, n)으로 가는 경로의 개수를 구하는 문제이다.

DP[i][j] = (i, j) 칸에 갈 수 있는 경로의 개수라고 하면 DP[1][1] = 1로 초기화한다.

 

(i, j)는 오른쪽 또는 아래로 이동하므로 (i+arr[i][j], j) 또는 (i, j+arr[i][j])로 이동한다.

 

총 시간 복잡도는 N^2 칸 * O(1) 이므로 O(N^2)이다.

 

import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int arr[][] = new int[n + 1][n + 1];
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				arr[i][j] = in.nextInt();
			}
		}

		long dp[][] = new long[n + 1][n + 1];
		dp[1][1] = 1;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {

				if (arr[i][j] == 0) {
					continue;
				}

				if (i + arr[i][j] <= n) {
					dp[i + arr[i][j]][j] += dp[i][j];
				}
				if (j + arr[i][j] <= n) {
					dp[i][j + arr[i][j]] += dp[i][j];
				}

			}
		}
		System.out.println(dp[n][n]);
	}
}

 

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 1509: 팰린드롬 분할  (0) 2020.07.21
boj 10942: 팰린드롬?  (0) 2020.07.20
boj 11660: 구간 합 구하기 5  (0) 2020.07.19
boj 1197: 최소 스패닝 트리  (0) 2020.07.19
boj 2357: 최솟값과 최댓값  (0) 2020.07.18

이 문제는 2차원에서의 누적 합을 구하는 문제이다.

 

sum[i][j]: (1, 1) ~ (i, j)까지의 합이라고 할 때,

sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + arr[i][j]와 같다

 

마지막으로 (x1, y1) ~ (x2, y2)의 값은 s[x2][y2] - s[x2][y-1] - s[x1-1][y2] + s[x1-1][y1-1]이다.

 

import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int m = in.nextInt();
		int arr[][] = new int[n + 1][n + 1];
		int sum[][] = new int[n + 1][n + 1];
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				arr[i][j] = in.nextInt();
				sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + arr[i][j];
			}
		}

		for (int i = 0; i < m; i++) {
			int x1 = in.nextInt();
			int y1 = in.nextInt();
			int x2 = in.nextInt();
			int y2 = in.nextInt();

			int ans = sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1];
			System.out.println(ans);
		}
	}
}

'알고리즘 공부 > boj' 카테고리의 다른 글

boj 10942: 팰린드롬?  (0) 2020.07.20
boj 1890: 점프  (0) 2020.07.20
boj 1197: 최소 스패닝 트리  (0) 2020.07.19
boj 2357: 최솟값과 최댓값  (0) 2020.07.18
boj 10986: 나머지 합  (0) 2020.07.18

+ Recent posts