StudyServer
web, server, java, spring 등.. 공부한 것을 기록하는 장소 입니다. 공부하면서 정리하였기 때문에 틀린 내용이 있을 수 있습니다. 이야기 해주시면 수정하겠습니다.

Interceptor(인터셉터)

2019-06-14 00:00:00 +0000

Interceptor

  • Interceptor란 컨트롤러를 실행할 때 별도의 처리를 할 수 있는 기능

JavaConfig 설정 방법

  • WebMvcConfigurer를 인터페이스 상속한 Servlet class에서 오버라이딩 해야한다
  • addInterceptors를 오버라이딩하여 InterceptorRegistration class를 사용해 interceptor class를 등록한다
  • addPathPatterns 함수로 interceptor가 가로챌 controller 범위를 설정할 수 있다
@Bean
public LoginInterceptor loginLogInterceptor() {
       return new LoginInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry)  {
       InterceptorRegistration interceptor =  registry.addInterceptor(loginLogInterceptor());
       interceptor.addPathPatterns("/**");
}
  • HandlerInterceptor를 인터페이스 상속받아 Interceptor 처리 클래스를 만든다
  • preHandle 함수는 Controller가 실행되기 전 호출된다
  • postHandle 함수는 View를 전부 그리기 전 호출된다 -afterCompletion 함수는 View를 그린 후 호출된다
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.HandlerInterceptor;
public class LoginInterceptor implements HandlerInterceptor {
      @Override
      public boolean preHandle(HttpServletRequest request,   HttpServletResponse response, Object handler)
                 throws Exception {
          return true;
      }
      
      @Override
      public void postHandle(HttpServletRequest request,   HttpServletResponse response, Object handler,
                 ModelAndView modelAndView) throws Exception {
     }
      
      @Override
      public void afterCompletion(HttpServletRequest request,   HttpServletResponse response, Object handler, Exception ex)
                 throws Exception {
      }   
}

Android Studio Install

2019-05-28 00:00:00 +0000

Android Studio Install

Android Install

  • download
  • Do not import settings 선택
  • Custom 선택
  • Performance, Android Virtual Device 선택
  • 설치 완료 후 제어판-시스템-고급-환경변수 선택
  • 시스템 변수에서 Path 편집. C:\Program Files\Android\Android Studio\jre\bin 추가 후 저장
  • 환경변수가 알맞게 잡혔는지 확인하기 위해서 cmd 창을 열고 keytool 입력. keytool 명령어에 대한 정보 출력
  • Android 설치 후 뜨는 창에서 Create New Project - Empty Activity 선택
  • App Name은 말 그대로 app의 이름
  • Package Name은 구글 플레이스토어에 앱의 고유식별자. 중복되면 안됨

AVD 추가

  • 삼성갤럭시 7의 높이, 너비를 가진 AVD를 생성한다
  • Tools - AVD - Create Virtual Device - New Hardware Profile 선택
  • Screen size 5.1
  • Resolution 1440x2560

Setting 수정

  • import를 자동으로 하도록 설정
  • File - Settings - Editor - General - Auto Import
  • Add unambiguous imports on the fly 체크
  • Optimize imports on the floy (for current project) 체크
  • Layout view에서 눈모양 아이콘을 클릭한 뒤 Show Layout Decorations 클릭.(앱 아이콘이 보여서 위치가 좀 더 정확해짐)

실행

  • Shift + F10 을 누르면 안드로이드 폰 화면이 생긴다

Simple Toast Example

  • layout에서 button을 TextView로 끌어서 놓는다
  • onClick 이벤트 이름으로 onClick이라고 적어둔다
  • 여기까지 하면 아래 xml이 작성된다. 그런데 Button이 빨간색이다. 위치 정보가 없어서 그렇다. 이 때 infer Constraints 버튼을 누르면 위치에 대한 정보가 생긴다
  • Before
<Button
    android:id="@+id/button4"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="onClick"
    android:text="Button"
    tools:layout_editor_absoluteX="167dp"
    tools:layout_editor_absoluteY="299dp" />
  • After
<Button
    android:id="@+id/button4"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="9dp"
    android:onClick="onClick"
    android:text="Button"
    app:layout_constraintBottom_toTopOf="@+id/textView"
    app:layout_constraintStart_toStartOf="@+id/textView" />
  • onClick 함수는 MainActivity에 정의해야한다
  • 실행해서 버튼을 누르면 짧은 Toast 메시지가 뜬다
public void onClick(View v) {
    Toast.makeText(getApplicationContext(),"Hello World",Toast.LENGTH_SHORT).show();
}

계층형 게시판

2019-05-20 00:00:00 +0000

계층형 게시판 만들기

  • 게시물 답글이 가능한 게시판.
  • parentSeq(자기 게시물 seq), order, depth 필드를 추가한다.
  • parentSeq는 자신이 최상위 게시물일 경우 자신의 seq, 답글일 경우 부모 게시물 seq를 저장한다
  • order 는 순서이다. 하나의 최상위 게시물로 묶여진 순서. 이 순서대로 출력된다(그러므로 답글이 달리면 답글 아래의 게시글들은 순서를 하나씩 미뤄야한다)
  • depth 는 깊이이다. 최상단이면 0, 최상단 게시물의 답글은 1, 그 답글의 답글은 2.. 이런식으로 늘어난다.\
  • order와 depth에 제한이 없도록 한다.

Index 규칙

  • 부모 게시물의 답글이 없다면 부모 게시물의 order+1, depth+1
  • 부모 게시물의 답글이 있다면 맨 마지막 게시물 정보에서 order+1

게시물 생성 규약

  • 클라이언트에게 자신의 부모 게시물 id을 받아야 한다
    1. 신규 게시글인지 답글인지 확인한다. 신규 게시글이면 게시물 생성 후 종료
    2. 부모 게시물 id로 부모에게 자식이 있는지 확인한다(확인하는 방법은 부모의 계층 정보에서 order+1, depth+1하고 동일한 부모게시물id로 가진 게시물이 있는지 확인하면 된다)
    3. 자식이 없다면 부모 정보를 기준으로 계층 정보를 넣어준다. 그리고 새로운 ordering 후 게시물 생성 및 종료 4, 자식이 있다면 마지막 자식을 찾는다. 그 마지막 자식을 기준으로 계층 정보를 넣어준다

DB 컬럼 추가

  • alter table board add parent_seq bigint(20) DEFUALT NULL;
  • alter table board add board_order bigint(20) DEFAULT 0;
  • alter table board add board_depth int DEFAULT 0;

VO 수정

  • 추가한 필드에 대응되는 멤버 변수 추가
     private long    parentSeq;
     private int       boardOrder;
     private long    boardDepth;

조회 쿼리 수정

  • 게시물 SEQ 순서가 아니라 부모 SEQ, order 순서대로 정렬해야한다.
  • 최신 게시물이 위로 올라가야하므로 부모 SEQ는 desc 정렬. 답글은 순서대로 출력되어야 하므로 ASC 정렬
  • select로 추가필드를 조회할 수 있도록 수정한다.
<select id="getTitleVOList" parameterType="SelectVO"  resultType="TitleVO">
           SELECT board_seq as boardSeq
                   , title
                   , writer
                   , date
                   , count
                   , user_id as userId
                   , user_seq as userSeq
                   , board_del as boardDel
                   , parent_seq as parentSeq
                   , board_order as boardOrder
                   , board_depth as boardDept  
           FROM board
           
           <include refid="searchBoard"></include>
           ORDER BY parent_seq DESC, board_order ASC
           LIMIT #{start}, #{length}  
     </select>

게시물 생성 코드

private PostReplyVO getMyRelpyVO(PostReplyVO parentReplyVo)  throws Exception {
           if (parentReplyVo == null) {
                throw new  LogicException(Constants.RESULT_STATE.BOARD_UNKOWN_ERROR.getState(), Constants.RESULT_STATE.BOARD_UNKOWN_ERROR.getMessage());                
           }
           
           PostReplyVO myReplyVO = new PostReplyVO();                 // 현재 게시물 자신의 정보
           myReplyVO.setParentSeq(parentReplyVo.getParentSeq());     // 최상위 부모 seq 넣어줌
           
           boolean isChild =  isParentFirstChild(parentReplyVo.getBoardSeq());
           if (!isChild) {                                                      // 자식이 존재하지 않는다
                PostReplyVO lastPostReplyVO =  dao.getPostReplyVO(parentReplyVo.getBoardSeq());  // 직계부모  정보를 가져와서 자신의 정보를 정한다
                if (lastPostReplyVO == null) {
                     throw new  LogicException(Constants.RESULT_STATE.BOARD_UNKOWN_ERROR.getState(), Constants.RESULT_STATE.BOARD_UNKOWN_ERROR.getMessage());
                }
                myReplyVO.setBoardOrder(lastPostReplyVO.getBoardOrder() +  1);
                myReplyVO.setBoardDepth(lastPostReplyVO.getBoardDepth() +  1);
                
           } else {
                PostReplyVO postReplyVO =  getMyParentLastChildBoardReplyVO(parentReplyVo);     // 자신의  부모의 마지막 자식을 찾음
                if (postReplyVO == null) {
                     throw new  LogicException(Constants.RESULT_STATE.BOARD_UNKOWN_ERROR.getState(), Constants.RESULT_STATE.BOARD_UNKOWN_ERROR.getMessage());
                }
                myReplyVO.setBoardOrder(postReplyVO.getBoardOrder() + 1);                // 마지막 자식의 정보를 가지고 자신의 정보를 정한다
                myReplyVO.setBoardDepth(parentReplyVo.getBoardDepth() +  1);  // 부모의 깊이에서 하나 더해주기
           }
           
           return myReplyVO;
     }

자식 있는지 확인 쿼리

<select id="getParentNextChildBoardCount"  parameterType="PostReplyVO" resultType="int">
   SELECT
                   count(*)
   FROM       board
   WHERE      parent_seq = #{parentSeq} and board_order  = #{boardOrder} + 1 and board_depth = #{boardDepth} + 1
</select>

부모 게시물의 마지막 자식을 찾음

<select id="getLastReplyBoard" resultType="PostReplyVO"  parameterType="ParamMap" >
   SELECT            
                     board_seq as boardSeq
                   , parent_seq as parentSeq
                   , board_order as boardOrder
                   , board_depth as boardDepth  
   FROM       board
   WHERE      parent_seq = #{parentSeq} and board_depth  >= #{boardDepth} + 1 and (board_order > #{boardOrder}) AND  board_state IN (0, 2)
   ORDER BY   board_order DESC
   LIMIT      0,1
</select>

VirtualBox Ubuntu 18.04.2 LTS

2019-05-20 00:00:00 +0000

VirtualBox Ubuntu 18.04.2 LTS

Download

  • VirtualBox Download
  • Ubuntu Server
  • 리눅스 서버가 필요하므로 Ubuntu 가 아닌 Ubuntu Server를 다운받는다. 그냥 Ubuntu는 GUI 운영체제이다
  • Ubuntu는 LTS(안정적이고 오랫동안 사용가능한 버전)을 Download 한다
  • Putty 설치
  • WinSCP 설치

Ubuntu 설정

  • 추가 버튼 클릭
  • 종류는 Linux, 버전은 Ubuntu (64-bit)로 설치
  • 메모리 2048MB(2GB) 설정
  • 지금 가상 드라이브 만들기
  • VDI(VirtualBox 디스크 이미지) 선택
  • 100GB 설정(사용드라이브가 1TB라서)
  • 설치 완료 후 ‘저장소’ 클릭. 컨트롤러:IDE 아래 비어있음을 클릭하고 CD 버튼을 누른다. 그리고 Ubuntu ISO 선택

Ubuntu 설치

  • 언어 선택(English)
  • Install Ubuntu
  • 파티션 설정 Done, Done, Use An Entire Disk, 계속 Done 하고 마지막에 Continue
  • ubuntu 로그인 id, pass 입력
  • 추가 패키지 설치는 넘어감

host 컴퓨터 정보 확인

  • 네트워크는 ‘어댑터에 브리지’ 하나만 사용
이더넷 어댑터 이더넷:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::881b:e340:c3c6:cae2%6
   IPv4 주소 . . . . . . . . . : 192.168.38.1
   서브넷 마스크 . . . . . . . : 255.255.192.0
   기본 게이트웨이 . . . . . . : 192.168.1.1

네트워크 설정

  • ssh 설치 및 ssh 시작
sudo apt-get install openssh-server
service ssh restart
  • 22번 포트 번호 열렸는지 확인
 netstat -tnlp
  • 만약 20번 포트가 없다면 등록한다.
  • 포트 등록하면서 재시작 해도 설정이 남는 iptables-persistent을 설치한다
sudo apt-get update
sudo apt-get install iptables-persistent
  • iptables 설정을 초기화한다(이 부분이 반드시 필요한지는 모르겠다)
  • localhost 접속 허용 규칙이나 22번 포트 열기 등… 의 처리를 한다
  • 출처
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -Z
sudo iptables -F
sudo iptables -X

고정 네트워크 IP 설정

  • UbuntuNetplan 설명
  • Ubuntu 17.10 부터 바뀐 네트워크 설정방법
  • Ubuntu 17.10 버전 이상이라면 interfaces을 설정해도 Netplan 설정에 덮어져 ip설정이 제대로 되지 않을 수 있다

Netplan 설정 방법

  • vi Netplan 수정
  • 50-cloud-init는 기본 인터페이스 설정
vi /etc/netplan/50-cloud-init.yaml
  • ethernets 아래에 설정할 네트워크 디바이스 이름을 추가한다.
  • addresses는 ip주소를 설정한다 /24는 서브넷마스크 대신 사용한다
  • /24의 의미는 왼쪽부터 채워진 1bit의 수. 즉 /24는 11111111.11111111. 11111111.0000 = 255.255.255.0 이다
  • enp0s3는 ifconfig로 네트워크 장비의 이름이다
  • netmask와 gateway는 host 컴퓨터 설정과 맞춰준다
network:
    ethernets:
        enp0s3:
            dhcp4: no
            dhcp6: no
            addresses: [192.168.38.3/24]
            gateway4: 192.168.1.1
            nameservers:
              addresses: [8.8.8.8,8.8.4.4]
    version: 2

설정 적용

sudo netplan apply

확인

ifconfig -a

TransactionAwareDataSourceProxy Error

2019-05-19 00:00:00 +0000

NoClassDefFoundError TransactionAwareDataSourceProxy Error

  • db 접속 테스트 코드 실행 시 발생
  • TransactionAwareDataSourceProxy class 를 찾을 수 없어서 나는 에러
  • TransactionAwareDataSourceProxy는 spring-jdbc안에 있다.
  • 현재 프로젝트의 spring-jdbc 버전에서 TransactionAwareDataSourceProxy가 없는 듯 그래서 현재 버전인 5.1.5.RELEASE 에서 5.1.4.RELEASE 로 바꿔주었더니 잘 되었다.
  • 진짜 5.1.5.RELEASE에 TransactionAwareDataSourceProxy가 선언안되어 있거나 다른 라이브러리랑 충돌나서 TransactionAwareDataSourceProxy를 인식하지 못하는 듯.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in base.toy.config.RootConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy
  • pom.xml
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>5.1.4.RELEASE</version>
</dependency>

Posts

subscribe via RSS