대부분의 현대 컴퓨터는 64비트 아키텍처를 사용한다. 따라서, 64비트 운영 체제에서 실행되는 소프트웨어는 더욱 빠르고 안정적으로 동작할 수 있다.

또한, 대부분의 최신 게임은 64비트 운영 체제에서 실행되는 것이 권장되고 있다. 이는 64비트 시스템이 더 높은 성능과 안정성을 제공하기 때문이다.

일부 오래된 하드웨어는 32비트 아키텍처를 사용한다. 예를 들어, 일부 오래된 노트북이나 데스크톱 컴퓨터는 32비트 운영 체제를 사용하고 있을 수 있다. 이러한 경우에는 일부 최신 소프트웨어가 작동하지 않을 수 있다.

64비트 운영 체제는 32비트 프로그램을 실행할 수 있다. 64비트 운영 체제에는 32비트 실행 파일을 실행할 수 있는 호환성 모드가 있다. 이 모드는 64비트 운영 체제에서 32비트 프로그램을 실행하기 위해 필요한 라이브러리와 다른 구성 요소를 제공한다.

이러한 호환성 모드는 64비트 운영 체제에서 32비트 애플리케이션을 실행하는 데 성공적으로 사용된다. 그러나, 이 모드는 더 많은 시스템 리소스를 사용하고, 일부 32비트 소프트웨어에서 성능 문제를 일으킬 수 있다.

32비트 운영 체제에서 64비트 프로그램을 실행하는 것은 불가능하다. 64비트 프로그램은 64비트 아키텍처를 사용하기 때문에, 32비트 운영 체제에서는 실행할 수 없다.

64비트 프로그램을 실행하려면 64비트 운영 체제가 필요하다. 64비트 운영 체제는 32비트 프로그램을 실행할 수 있지만, 32비트 운영 체제에서는 64비트 프로그램을 실행할 수 없다.

따라서, 64비트 프로그램을 실행하려면 64비트 운영 체제를 설치해야 한다. 64비트 운영 체제를 설치하면 64비트 프로그램을 실행할 수 있고, 32비트 프로그램도 호환성 모드를 통해 실행할 수 있다.

32비트와 64비트의 의미는 메모리 주소(bus width)의 크기를 나타내는 것이다.

32bit와 64bit의 의미

32비트와 64비트의 의미는 메모리 주소(bus width)의 크기를 나타내는 것이다.

32비트 시스템에서는 메모리 주소(bus width)가 32비트이며, 32비트는 2^32(2의 32제곱)(약 42억 9천만)개의 메모리 주소를 가질 수 있다. 따라서, 32비트 시스템은 최대 4GB(2^32 바이트)의 메모리를 처리할 수 있다.

반면에, 64비트 시스템에서는 메모리 주소(bus width)가 64비트이며, 64비트는 2^64(약 18 백경)개의 메모리 주소를 가질 수 있다. 따라서, 64비트 시스템은 32비트 시스템보다 훨씬 더 큰 양의 메모리를 처리할 수 있다.

결론적으로, 32비트와 64비트는 메모리 주소(bus width)의 크기를 나타내며, 이는 시스템이 처리할 수 있는 메모리의 양을 결정한다. 64비트 시스템은 32비트 시스템보다 더 큰 양의 메모리를 처리할 수 있기 때문에, 더욱 높은 성능을 제공할 수 있다.

 

 

출처: 혼자 공부하는 컴퓨터 구조+운영체제

'Developer 지식' 카테고리의 다른 글

OSI 7계층  (0) 2023.04.21
Jupyter nootbook 설치 및 Anaconda Prompt 설치 및 Jupyter nootbook 설정  (0) 2023.04.21
high address,low address  (0) 2023.04.13
AJAX  (0) 2023.04.13
소프트웨어와 하드웨어의 기본 이해  (0) 2023.04.13

High address와 Low address는 컴퓨터 메모리의 두 방향을 나타내는 용어이다.

Low address는 메모리의 시작 부분을 가리키며, 보통 값이 작은 주소를 가리킨다. High address는 메모리의 끝 부분을 가리키며, 보통 값이 큰 주소를 가리킨다.

주소값은 CPU 아키텍처에 따라 다르지만, 대개는 메모리 주소의 첫 번째 바이트부터 마지막 바이트까지 16진수로 표현된다. 따라서 Low address는 0x00000000으로 시작하고 High address는 0xFFFFFFFF(32비트 시스템의 경우) 또는 0xFFFFFFFFFFFFFFFF(64비트 시스템의 경우)로 끝난다.

Low address와 High address는 주로 포인터(Pointer)나 배열(Array)과 같은 데이터 구조에서 사용된다. 포인터나 배열의 시작 주소를 나타낼 때 Low address를 사용하고, 데이터 구조의 끝을 나타낼 때 High address를 사용한다.

예를 들어, 다음과 같은 배열을 생각해보자:

int arr[] = {1, 2, 3, 4, 5};


배열의 첫 번째 요소인 1은 arr[0]에 저장되어 있으며, 이는 배열의 Low address를 나타낸다. 배열의 마지막 요소인 5는 arr[4]에 저장되어 있으며, 이는 배열의 High address를 나타낸다.

AJAX

AJAX란 '비동기식 자바스크립트와 XML'의 약자입니다. 이는 전체 페이지를 새로 고치지 않고도 페이지 내용을 업데이트할 수 있는 웹 페이지를 만드는 기술입니다. 자바스크립트를 사용하여 서버에 비동기식 요청을 보내고 페이지 내용을 동적으로 업데이트함으로써 이를 구현합니다.

AJAX를 사용하면 데이터를 서버에서 가져와 페이지를 전체적으로 새로 고치지 않고도 페이지를 업데이트할 수 있으므로 더 빠르고 더 매끄러운 사용자 경험을 제공할 수 있습니다. 요즘에는 JSON이 데이터 형식으로 더 많이 사용되어 AJAX 기반 애플리케이션에서 클라이언트와 서버 간 데이터를 교환하는 데 사용됩니다.

ajax 예시

예를 들어, 웹 페이지에 코멘트를 추가하는 기능이 있다고 가정해봅시다. 일반적으로 사용자는 코멘트를 작성하고 "제출" 버튼을 클릭합니다. 그러면 전체 페이지가 새로고침되고 새로운 코멘트가 표시됩니다.

그러나 AJAX를 사용하면 전체 페이지를 새로 고치지 않고도 새로운 코멘트를 추가할 수 있습니다. 사용자가 "제출" 버튼을 클릭하면, 자바스크립트가 서버에 비동기식으로 요청을 보내서 데이터를 가져옵니다. 그런 다음, 자바스크립트는 페이지의 일부를 업데이트하여 새로운 코멘트를 추가합니다. 이렇게하면 새로운 코멘트가 페이지에 바로 표시되고, 사용자는 페이지 전체를 새로 고침하지 않아도 됩니다.

다른 예시로는, 사용자가 검색어를 입력하고, 자동완성 기능이 제공되는 검색 엔진이 있다고 가정해봅시다. 이 경우, 자바스크립트를 사용하여 사용자가 검색어를 입력할 때마다 서버에 요청을 보내고, 검색어와 일치하는 결과를 가져와서 페이지에 동적으로 업데이트할 수 있습니다. 이를 통해 사용자는 검색어를 입력할 때마다 자동완성 기능을 통해 빠르게 검색 결과를 확인할 수 있습니다.

// when the form is submitted, send an AJAX request to add the new comment
document.getElementById('comment-form').addEventListener('submit', function(event) {
  // prevent the default form submission
  event.preventDefault();

  // get the input value and clear the input field
  var commentText = document.getElementById('comment-input').value;
  document.getElementById('comment-input').value = '';

  // create a new XMLHttpRequest object
  var xhr = new XMLHttpRequest();

  // set up the request
  xhr.open('POST', '/add_comment');

  // set up the request headers
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

  // set up the request body
  var requestBody = 'comment=' + encodeURIComponent(commentText);

  // handle the response
  xhr.onload = function() {
    if (xhr.status === 200) {
      // when the request is successful, add the new comment to the list
      var newComment = document.createElement('li');
      newComment.textContent = JSON.parse(xhr.responseText).comment;
      document.getElementById('comment-list').appendChild(newComment);
    } else {
      alert('Failed to add comment');
    }
  };

  // handle network errors
  xhr.onerror = function() {
    alert('Network error');
  };

  // send the request
  xhr.send(requestBody);
});

// when the page loads, send an AJAX request to get the initial comments
var xhr = new XMLHttpRequest();
xhr.open('GET', '/get_comments');

xhr.onload = function() {
  if (xhr.status === 200) {
    // when the request is successful, add the initial comments to the list
    var comments = JSON.parse(xhr.responseText).comments;

    for (var i = 0; i < comments.length; i++) {
      var comment = document.createElement('li');
      comment.textContent = comments[i];
      document.getElementById('comment-list').appendChild(comment);
    }
  } else {
    alert('Failed to get comments');
  }
};

xhr.onerror = function() {
  alert('Network error');
};

xhr.send();

 

'Developer 지식' 카테고리의 다른 글

32bit와 64bit  (0) 2023.04.13
high address,low address  (0) 2023.04.13
소프트웨어와 하드웨어의 기본 이해  (0) 2023.04.13
웹 크롤링 설명/관련 질문  (0) 2023.04.13
CSR&SSR  (0) 2023.04.13

"소프트웨어와 하드웨어는 컴퓨터 시스템의 핵심 구성 요소이다."

 

소프트웨어와 하드웨어의 차이점과 각각의 역할을 알아보자.

 

소프트웨어(Software)

소프트웨어는 컴퓨터 시스템에서 사용되는 프로그램, 데이터, 명령 등 논리적인 부분을 의미한다. 소프트웨어는 컴퓨터 시스템의 동작을 제어하며, 사용자가 필요로 하는 기능을 수행하고, 데이터를 처리, 저장, 전송하는 역할을 한다. 소프트웨어는 대표적으로 다음과 같이 분류된다.


①.애플리케이션 소프트웨어
②.시스템 소프트웨어
③.라이브러리
④.프로그래밍 언어

 

하드웨어(Hardware)

하드웨어는 컴퓨터 시스템의 물리적인 부분을 의미한다. 전자 기기로 구성된 하드웨어는 소프트웨어의 동작을 지원하고 사용자와 컴퓨터 시스템 간의 상호작용을 가능하게 한다. 하드웨어는 일반적으로 컴퓨터의 성능, 기능, 용량 등을 결정하는 역할을 수행한다. 대표적인 하드웨어 예시는 다음과 같다.

①.CPU
②.메모리
③.저장장치
④.입출력 장치
⑤.모니터
⑥.키보드

컴퓨터 시스템은 소프트웨어와 하드웨어의 상호 작용으로 구성되어 있다. 소프트웨어는 논리적인 부분을 담당하며, 다양한 기능과 데이터 처리를 수행한다. 반면 하드웨어는 물리적인 부분을 담당하며, 컴퓨터 시스템의 성능과 용량을 결정하고 사용자와의 상호작용을 지원한다. 이 두 요소가 서로 협력하여 컴퓨터 시스템이 원활하게 작동하도록 한다.


'Developer 지식' 카테고리의 다른 글

high address,low address  (0) 2023.04.13
AJAX  (0) 2023.04.13
웹 크롤링 설명/관련 질문  (0) 2023.04.13
CSR&SSR  (0) 2023.04.13
단위테스트 AAA  (0) 2023.04.13

데이터 전송을 처리하는 프로그램 작성 시, 중요한 개념 중 하나는 DTO(Data Transfer Object)이다. Java에서의 DTO 개념과 사용 이유에 대해 설명한다.

 

DTO는 보통 데이터베이스의 각 테이블에서 가져온 데이터를 담아서 사용한다. 이를 통해 데이터를 전송하는 과정에서 데이터를 캡슐화하고, 비즈니스 로직과 데이터베이스 간의 데이터 교환을 단순화한다.

DTO를 사용하는 이유는 데이터베이스와 비즈니스 로직 간의 결합도를 낮추기 위함이다. 즉, 데이터베이스의 변경에 영향을 받지 않고 비즈니스 로직을 수정할 수 있도록 해주는 것이다. 또한 DTO를 사용하면 데이터 전송 시 데이터의 무결성을 보장할 수 있다.

간단히 말해, DTO는 데이터 전송에 필요한 객체로, 데이터베이스나 외부 시스템에서 가져온 데이터를 비즈니스 로직에서 사용할 수 있는 형태로 변환해주는 역할을 한다. 이를 통해 데이터의 무결성을 보장하고, 데이터베이스와 비즈니스 로직 간의 결합도를 낮출 수 있다.

예를 들어, 고객 정보를 데이터베이스에서 가져와서 비즈니스 로직에서 사용해야 하는 경우를 생각해보겠다.

데이터베이스에서는 고객 정보를 다음과 같은 형태로 저장할 수 있다.

Customer table

-----------------------------

| ID | Name | Age | Address |

-----------------------------

| 01 | Tom | 30 | Seoul |

| 02 | Jane | 25 | Busan |

-----------------------------

 

이때, 고객 정보를 비즈니스 로직에서 사용하기 위해서는 데이터베이스의 테이블과는 다른 형태로 변환해야 한다. 이때 DTO를 사용하면 다음과 같이 변환할 수 있다.

public class CustomerDTO {
    private String id;
    private String name;
    private int age;
    private String address;

    public CustomerDTO(String id, String name, int age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }
}

위와 같이 DTO 클래스를 작성하면, 데이터베이스에서 가져온 고객 정보를 DTO 객체에 담아서 비즈니스 로직에서 사용할 수 있다. 이를 통해 데이터베이스와 비즈니스 로직 간의 결합도를 낮출 수 있다.

데이터베이스와 연동하여 데이터를 조작하는 프로그램 작성 시, 중요한 개념 중 하나는 DAO(Data Access Object)이다.  Java에서의 DAO 개념과 사용 이유에 대해 설명하겠다.

 

Java에서 DAO는 Data Access Object의 약어로, 데이터베이스와 연동하여 데이터를 조작하는 객체를 말한다.

DAO는 데이터베이스와의 연결을 관리하고, 데이터베이스에서 데이터를 가져오거나 데이터를 저장하는 등의 역할을 수행한다. DAO는 보통 인터페이스로 작성되어 있고, 실제로는 이 인터페이스를 구현하는 클래스를 사용한다.

DAO는 데이터베이스와 비즈니스 로직 간의 결합도를 낮추는데 큰 역할을 한다. 데이터베이스가 변경되어도 비즈니스 로직이 영향을 받지 않도록 해주며, 코드의 재사용성과 유지보수성을 높여준다.

DAO를 사용하면 데이터베이스와의 연결과 데이터베이스 조작을 캡슐화할 수 있으므로, 비즈니스 로직에서는 단순히 DAO의 메서드를 호출함으로써 데이터베이스 조작을 수행할 수 있다. 이를 통해 코드의 가독성과 유지보수성을 높일 수 있다.

간단히 말해, DAO는 데이터베이스와 연동하여 데이터를 조작하는 객체로, 데이터베이스와 비즈니스 로직 간의 결합도를 낮추고 코드의 재사용성과 유지보수성을 높여주는 것이다.

예를 들어, 사용자 정보를 데이터베이스에서 가져오는 기능을 DAO를 사용하여 구현하는 예를 생각해 보겠다.

데이터베이스에서는 사용자 정보를 다음과 같은 형태로 저장할 수 있다.

User table

------------------------

| ID | Name | Address |

------------------------

| 01 | Tom | Seoul |

| 02 | Jane | Busan |

| 03 | Alice | Daegu |

------------------------

이때, 사용자 정보를 데이터베이스에서 가져와서 비즈니스 로직에서 사용하기 위해서는 DAO를 사용하여 다음과 같이 구현할 수 있다.

public interface UserDao {
    List getAllUsers();
    User getUserById(String id);
}

public class UserDaoImpl implements UserDao {
    private Connection conn;

    public UserDaoImpl(Connection conn) {
        this.conn = conn;
    }

    @Override
    public List getAllUsers() {
        List users = new ArrayList<>();
        try (Statement stmt = conn.createStatement()) {
            String query = "SELECT * FROM User";
            ResultSet rs = stmt.executeQuery(query);
            while (rs.next()) {
                String id = rs.getString("ID");
                String name = rs.getString("Name");
                String address = rs.getString("Address");
                User user = new User(id, name, address);
                users.add(user);
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        return users;
    }

    @Override
    public User getUserById(String id) {
        User user = null;
        try (PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM User WHERE ID = ?")) {
            pstmt.setString(1, id);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                String name = rs.getString("Name");
                String address = rs.getString("Address");
                user = new User(id, name, address);
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        return user;
    }
}

위와 같이 UserDao 인터페이스를 정의하고, UserDaoImpl 클래스를 구현하여 DAO를 구현할 수 있다. UserDaoImpl 클래스에서는 Connection 객체를 사용하여 데이터베이스와 연결하고, getAllUsers() 메서드와 getUserById() 메서드를 구현하여 사용자 정보를 가져올 수 있다. 이를 통해 데이터베이스와 비즈니스 로직 간의 결합도를 낮추고, 코드의 재사용성과 유지보수성을 높일 수 있는 것이다.

DTO: Data Transfer Object

DAO: Data Access Object

DAO와 DTO는 둘 다 데이터베이스와 연관된 기능을 수행하는 객체이지만, 각각의 역할과 목적이

다르다.


DAO는 데이터베이스와 연결을 관리하고, 데이터베이스에서 데이터를 가져오거나 데이터를 저장하는 등의 역할을 수행한다. 즉, DAO는 데이터베이스와의 연결과 데이터베이스 조작을 캡슐화하는 객체이다.

"조작을 캡슐화한다"는 말은, 데이터베이스와의 조작을 한 곳에 모아서 캡슐화하는 것을 의미. 이것은 다시 말해, 데이터베이스와의 연결을 추상화하고, 데이터베이스에서 데이터를 가져오는 방법과 저장하는 방법을 명확하게 구분하는 것.

예를 들어, DAO를 사용하지 않고 직접 데이터베이스와 연결하여 SQL 쿼리를 작성하고 데이터를 가져오는 코드를 작성한다면, 코드가 복잡해지고 유지보수가 어려워지는데, 이 때, DAO를 사용하면 데이터베이스 연결과 SQL 쿼리 작성 등을 한 곳에서 캡슐화하므로, 코드가 간결해지고 유지보수가 쉬워진다.

반면, DTO는 데이터를 전송하는데 사용되는 객체로, 데이터베이스나 외부 시스템에서 가져온 데이터를 비즈니스 로직에서 사용하기 쉽게 변환해주는 역할을 한다. DTO는 데이터를 전송하는 과정에서 데이터를 캡슐화하고, 비즈니스 로직과 데이터베이스 간의 데이터 교환을 단순화한다.

따라서 DAO와 DTO는 각각의 역할과 목적이 다르다. DAO는 데이터베이스와의 연결과 데이터베이스 조작을 캡슐화하며, DTO는 데이터 전송을 캡슐화한다. DAO와 DTO는 데이터베이스와 연동하는 기능을 구현하는 데 사용되는 객체이지만, 다른 방식으로 된다.


사용자가 로그인을 시도하면 클라이언트는 사용자가 입력한 정보를 서버로 전송하고, 서버는 해당 정보를 검증하여 로그인 결과를 클라이언트로 전송한다. 이때 DTO는 클라이언트와 서버 간데이터 전송을 캡슐화하는 데 사용된다.

또한, DTO는 서버 사이드에서도 사용될 수 있다. 예를 들어, 서버 사이드에서 데이터베이스에서 가져온 정보를 DTO로 변환하여 비즈니스 로직으로 전달할 수 있다. 이를 통해 비즈니스 로직에서 데이터베이스와의 결합도를 낮추고, 데이터 전송 시 데이터의 무결성을 보장할 수 있다.


DAO로 데이터베이스 연결을 한다면, 일반적으로 최초 1회에 한해 연결이 수행된다. 이후 DAO 객체를 재사용하면 이미 연결된 데이터베이스와 계속해서 작업할 수 있다.

하지만, 연결된 데이터베이스와 일정 시간 이상 연결이 유지되지 않으면 연결이 끊어지는 경우도 있다. 이 경우 DAO 객체를 다시 사용하기 전에 데이터베이스와 연결을 다시 수행해야 한다.

DAO는 데이터베이스와 연결하여 데이터를 조작하는 기능을 담당한다. 이를 통해 비즈니스 로직에서 데이터베이스와의 결합도를 낮추고, 코드의 재사용성과 유지보수성을 높일 수 있다.

 

DAO로 데이터베이스를 조작하는 방법은 다양하다. 보통 "JDBC(Java Database Connectivity) API"를 사용하여 데이터베이스와의 연결 및 데이터 조작을 수행한다.

 

JDBC는 Java에서 데이터베이스와의 연결을 위한 표준 API로, 다양한 데이터베이스와 호환된다.

DAO에서는 JDBC API를 사용하여 SQL문을 작성하고, 이를 데이터베이스에 전달하여 데이터를 조작한다. SQL문은 SELECT, INSERT, UPDATE, DELETE 등의 다양한 종류가 있으며, 데이터베이스와 상황에 따라 적절한 SQL문을 사용하여 데이터를 처리한다.

또한, DAO에서는 JDBC API를 사용하여 데이터베이스 연결 및 연결 해제, 데이터 삽입, 수정, 삭제 등의 기능을 수행한다. 이러한 기능을 캡슐화하여 비즈니스 로직에서는 DAO의 메서드를 호출함으로써 데이터베이스 조작을 수행할 수 있다.

 

따라서, DAO는 JDBC API를 사용하여 데이터베이스와 연결하고, SQL문을 작성하여 데이터를 조작하고. 이를 통해 데이터베이스와 비즈니스 로직 간의 결합도를 낮추고, 코드의 재사용성과 유지보수성을 높일 수 있는 친구다.

웹 크롤링(Web Crawling)은 인터넷 상의 웹 페이지에서 데이터를 모으거나 추출하는 과정을 의미한다. 크롤러(Crawler)로도 불리며, 다양한 웹 페이지를 찾아가 정보를 수집한 후, 분석 및 가공하여 원하는 정보를 얻어내는 작업을 수행한다.

웹 크롤링은 대개 자동화된 프로그램을 이용해 진행되며, 이를 통해 인터넷에 있는 다양한 정보들을 취합하고 분석할 수 있다. 그 결과, 특정 웹 사이트나 주제에 대한 정보를 쉽게 모으고 분석할 수 있다.

보통 웹 크롤링은 두 가지 방법으로 이루어진다.

첫 번째 방법은 웹 페이지의 HTML 소스 코드를 직접 다운로드하여 데이터를 추출하는 방식이다.

두 번째 방법은 웹 API(Application Programming Interface)를 활용하여 데이터를 추출하는 방식이다.

그러나 웹 크롤링은 불법적인 목적으로 사용될 가능성도 있고, 많은 웹 페이지를 무차별적으로 방문하여 데이터를 모으는 것은 웹 사이트에 부담을 줄 수 있다. 그래서 웹 크롤링을 할 때는 관련 법률과 웹 사이트의 이용 규정을 따르고, 부담을 줄이기 위해 적절한 지연 시간을 두는 등의 조치를 취해야 한다.

웹 크롤러 봇이란 무엇인가?
웹 크롤러 봇(Web Crawler Bot)은 웹 페이지를 찾아가 데이터를 모으는 봇(Bot) 중 하나로, 크롤링 작업을 자동화한 프로그램이다. 봇이란 자동화된 프로그램을 가리키며, 웹 크롤러 봇은 웹 페이지를 찾아가 데이터를 모으고, 이를 분석하여 필요한 정보를 추출하는 작업을 자동화하여 수행한다.

웹 크롤러 봇은 주로 검색 엔진에서 활용된다. 검색 엔진은 많은 웹 페이지를 크롤링하여 내용을 색인화하고, 이를 바탕으로 검색 결과를 제공한다. 이런 검색 엔진은 웹 크롤러 봇을 이용해 웹 페이지를 자동으로 크롤링하여 정보를 모으고, 이를 색인화한다.

웹 크롤러를 이용해 사용자가 자주 방문한 키워드로 광고를 볼 수 있게 할 수 있을까?

사용자가 자주 방문한 키워드를 기반으로 광고를 제공하는 것은 가능하다.

이를 위해서는 사용자가 방문한 웹 페이지의 정보를 수집하고, 이를 분석하여 사용자의 관심사를 파악하는 과정이 필요하다. 웹 크롤러를 이용하여 사용자가 방문한 웹 페이지의 정보를 수집할 수 있으며, 이를 통해 사용자의 관심사를 파악하고 이에 맞는 광고를 제공할 수 있다.

하지만, 이를 위해서는 사용자의 동의가 필요하며, 개인정보 보호와 관련된 법령을 준수해야 한다. 또한, 사용자가 방문한 웹 페이지의 정보를 수집할 때에는 해당 웹 페이지의 이용 규정을 준수해야 하며, 부담을 덜어내기 위해 적절한 딜레이를 두는 등의 조치를 취해야 한다.

또한, 이러한 기능을 제공하기 위해서는 웹 사이트 운영자와의 협업이 필요하다. 사용자가 방문한 웹 페이지의 정보를 수집하고, 이를 기반으로 광고를 제공하는 것은 해당 웹 페이지의 운영자와의 계약이나 협의를 통해 이루어져야 한다. 따라서, 이를 위해서는 웹 사이트 운영자와의 협력과 협업이 필수적이다.

 

웹 크롤러를 이용하여 사용자가 방문한 웹 페이지의 정보를 어떻게 수집 할까?

 

웹 크롤러는 HTTP 프로토콜을 통해 웹 페이지의 HTML 코드를 수집한다. 웹 페이지의 HTML 코드는 웹 브라우저에서 해당 페이지를 열었을 때 보이는 내용을 구성하는 코드로, 웹 크롤러는 이 코드를 분석하여 다양한 정보를 추출해요. 이를 위해 웹 크롤러는 다양한 기술을 사용하여 HTML 코드를 분석하고, 필요한 정보를 추출한다.

예를 들어, 웹 페이지에서 상품 정보를 수집하는 경우, 웹 크롤러는 웹 페이지의 HTML 코드에서 상품 정보를 구성하는 태그를 찾아내고, 해당 태그의 속성 값을 추출한다. 이후, 추출한 상품 정보를 데이터베이스나 파일 등에 저장하여, 다양한 용도로 활용할 수 있다.

그리고, 웹 크롤러는 자동화된 방식으로 웹 페이지를 탐색하기 때문에, 수집 대상 페이지에 대한 URL 목록을 수동으로 입력하는 것보다 더 많은 정보를 수집할 수 있어요. 이러한 특성을 이용하여, 웹 크롤러는 다양한 용도로 활용된다.

                                                                 웹 크롤러와 알고리즘의 연관성
웹 크롤러와 알고리즘은 밀접한 관련이 있다. 웹 크롤러는 웹 페이지에서 데이터를 추출하기 위한 알고리즘을 포함한다. 이 알고리즘은 웹 페이지의 HTML 소스 코드를 분석하고, 필요한 정보를 추출하기 위해 사용된다. 예를 들어, 웹 크롤러는 웹 페이지의 링크를 추출하고, 이를 따라가며 다른 웹 페이지를 방문하여 데이터를 추출할 수 있다. 이러한 작업에서 사용되는 알고리즘은 BFS(Breadth-First Search)나 DFS(Depth-First Search) 등과 같은 그래프 탐색 알고리즘을 기반으로 한다.

또한, 웹 크롤러는 데이터 수집을 위해 여러 가지 알고리즘을 사용할 수 있다. 예를 들어, 특정 웹 페이지에서 특정 패턴을 찾아내기 위해 정규 표현식을 사용할 수 있고, 텍스트 마이닝 알고리즘을 사용하여 키워드를 추출할 수도 있다.

마지막으로, 웹 크롤러에서는 데이터 추출 과정에서 생기는 문제를 해결하기 위해 다양한 알고리즘을 사용할 수 있다. 예를 들어, 크롤러가 반복해서 이미 방문한 웹 페이지를 다시 방문하는 경우를 해결하기 위해, 이전에 방문한 웹 페이지를 기억하는 알고리즘을 사용할 수 있다. 이렇게 웹 크롤러에서 사용되는 알고리즘은 데이터 수집 및 분석을 효과적으로 수행하는 데 필수적이다.

 

웹 크롤러 봇은 JS코드를 읽을 수 없을까?

크롤러 봇은 JavaScript 코드를 읽을 수는 있지만, 이를 분석하는 데 제약이 있을 수 있다.

대부분의 웹 크롤러는 JavaScript 코드를 실행하지 않고, HTML 소스 코드만을 분석한다.

이는 대부분의 웹 페이지에서는 문제가 없지만, 최근에는 JavaScript를 이용한 동적 웹 페이지가 많이 등장하면서, 웹 크롤러에서는 JavaScript 코드를 실행하는 경우가 더 많아지고 있다.

 

그러나, 웹 크롤러가 JavaScript 코드를 정확히 실행할 수 있는 것은 아니다. JavaScript 코드에는 동적으로 생성되는 요소나, 비동기로 로딩되는 요소 등이 있을 수 있으며, 이를 웹 크롤러가 정확히 처리하지 못할 경우, 데이터 수집에 문제가 생길 수 있다.

따라서, 웹 크롤러를 개발할 때에는 웹 페이지의 구조와 JavaScript 코드를 정확하게 분석하여, 필요한 데이터를 정확하게 수집할 수 있도록 구현해야 한다. 또한, 웹 페이지에서 동적으로 로딩되는 데이터를 수집하기 위해서는 AJAX 등의 기술을 사용하여, JavaScript 코드를 실행하고, 동적으로 생성되는 요소를 처리해야 한다.

 

 

일부 광고주들이 사용자의 검색 기록이나 이전 검색 내역 등을 바탕으로 광고를 보이는 것이 있다는건, 웹 크롤러가 유저의 데이터를 수집한 것을 광고주가 가져왔다는 것일까?

일반적으로 광고주들은 웹 크롤러를 사용하여 사용자의 검색 기록이나 이전 검색 내역 등을 수집하지는 않는다. 대신, 광고주들은 검색 엔진 등의 기술을 이용하여 사용자의 검색어를 수집하고, 이를 바탕으로 광고를 타겟팅한다.

예를 들어, 광고주가 특정 키워드를 타겟팅하기 위해 구글 애드워즈와 같은 광고 서비스를 이용하는 경우, 광고주는 특정 키워드에 대한 광고를 등록한다. 이후, 사용자가 해당 키워드로 검색할 경우, 광고 서비스는 사용자의 검색어를 수집하고, 이를 바탕으로 해당 광고를 노출한다.

이러한 광고는 광고 서비스에서 제공하는 기능으로, 광고주가 사용자의 개인정보를 수집하는 것은 불법적인 활동이다. 따라서, 광고주들은 사용자의 검색어 등을 수집하기 위해 웹 크롤러를 사용하는 것은 아니며, 광고 서비스를 이용하여 검색어를 수집한다.

검색 엔진을 이용하여 수집되는 검색어는 검색 엔진에서 제공하는 검색 서비스를 이용하는 모든 사용자들의 검색어를 수집한다. 따라서, 네이버나 다음과 같은 검색 엔진에서 제공하는 검색 서비스를 이용하는 모든 사용자들의 검색어가 수집 대상이 된다.

또한, 검색 엔진은 웹 크롤러를 이용하여 전체 인터넷 상의 웹 페이지를 수집한다. 이때, 웹 크롤러는 검색 엔진에서 설정한 기준에 따라 웹 페이지를 수집하게 되며, 이를 바탕으로

검색 엔진에서 검색 결과를 생성한다. 따라서, 검색 엔진을 이용하여 수집되는 정보는 검색어뿐만 아니라, 웹 페이지 내용, 링크 정보 등 다양한 정보를 수집한다.

 

검색엔진에 대하여

검색 엔진은 웹 페이지 내용, 링크 정보 등 다양한 정보를 수집한다. 검색 엔진은 크롤러라는 프로그램을 사용하여 웹 페이지를 수집하고, 이를 인덱싱하여 검색어에 대한 검색 결과를 제공한다. 크롤러는 웹 페이지의 HTML 코드를 수집하며, 이를 파싱하여 웹 페이지 내용을 추출하고, 링크 정보를 수집하여 다음에 방문할 웹 페이지를 결정한다.

검색 엔진에서 수집되는 정보는 검색어, 웹 페이지 내용, 링크 정보 뿐만 아니라, 이미지, 동영상, 문서 파일 등 다양한 종류의 정보를 수집한다. 이러한 정보들은 검색 결과 페이지에 표시되며, 검색 결과 페이지에서 사용자는 원하는 정보를 찾을 수 있다.

따라서 검색 엔진은 다양한 정보를 수집하여 사용자에게 제공하며, 이를 위해 크롤러라는 프로그램을 사용한다.

'Developer 지식' 카테고리의 다른 글

AJAX  (0) 2023.04.13
소프트웨어와 하드웨어의 기본 이해  (0) 2023.04.13
CSR&SSR  (0) 2023.04.13
단위테스트 AAA  (0) 2023.04.13
Thymeleaf에서 사용자 정의 속성을 이용한 에러 처리  (0) 2023.04.13

CSR&SSR

* 영상 출처: https://www.youtube.com/watch?v=YuqB8D6eCKE

CSR&SSR을 이야기 하기 전에

먼저 SPA,MPA에 대한 이야기를 해야한다.

오늘 날, 웹페이지 개발을 할 때는 react,vue 등 js 기반 SPA로 작성하게 된다.

SPA란 "Single Page Application"의 약자로 하나의 페이지로 구성된 웹 어플리케이션 이다.

어플리케이션을 이용할 때 Header는 고정되어 있고

메뉴를 선택하면 메인화면 부분,혹은 클릭한 부분만 바뀌는 그런 사이트.

(00:48)

(00:49)

이러한 웹사이트들이 SPA이다.

반면 MPA란 "Multi page Application"의 약자로

탭을 이동할 때마다 서버로부터 새로운 HTML을 새로 받아와서 페이지 전체를 새로 렌더링하는

전통적인 웹 페이지 구성 방식이다.

이와 같이 여전히 MPA를 사용하는 사이트들이 있기는 하지만

매번 새로운 HTML을 서버로부터 받아오고, 전환 시마다 화면 깜빡이는 단점들이 있기에

AJAX가 등장하고 나서 부터는 원하는 부분만 클라이언트에서 동적으로 갈아끼울 수 있고

화면 깜빡임도 없는 SPA를 사용하게 되었다.

(01:36)

일반적으로 SPA에서는 렌더링 방식으로 CSR을

MPA에서는 렌더링 방식으로 SSR을 사용한다.

SPA는 웹 어플리케이션을 필요한 정적 리소스를 초반 한 번에 모두 다운로드 하고

그 이후 그 이후 새로운 페이지 요청이 있을 때 갱신에 필요한 데이터만 전달받아서 클라이언트에서 페이지를 갱신하기 때문에 자연스럽게 렌더링 방식으로 CSR을 사용하게 되고

MPA는 새로운 요청이 있을 때마다 서버에서 이미 렌더링된 방식으로 SSR을 사용하게 된다.

리액트,뷰,앵귤러를 사용해서 SPA를 만들고 특별한 목적을 가지고 렌더링 방식을 변경하지 않는다면 자연스럽게 CSR을 사용하게 되고,

PHP나,JSP로 MPA를 만들면 자연스럽게 SSR을 사용하게 된다는 것이다.

(02:34)

대부분의 웹어플리케이션 가장 많이 사용되는 렌더링 방식은 CSR인데.

가장 좋은 렌더링 방식이기 때문에 사람들이 가장 많이 사용하는 걸까? 본격적으로 알아보자. CSR이란 Client side Rendering의 약자로 클라이언트 측에서 렌더링하는 방식이고

SSR이란 Server side Rendering의 약자로 서버측에서 렌더링하는 방식이다.

말 그대로 어느 쪽에서 Render을 준비하는지에 따라 나뉘는 개념이라고 할 수 있다.

CSR과 SSR을 공부할 때, SSG도 함께 언급되곤 하는데

SSG는 Static site Generation의 약자로 Static Rendering이라고도 불리는 방식이다.

(03:23)

서버에서 HTML을 보내준다는 측면에서는 SSR과 비슷하지만

언제 만들어 주느냐에 차이가 있다.

(03:30)

(03:39)

동작 과정이 구체적으로 어떻게 다른지? 그리고 그에 따라 나타나는 특징에 대해 알아보자.

CSR의 동작 과정과 중요 특징.

(04:42)

JS 파일을 다운로드 받아 동적으로 페이지를 만들어서 띄운다는 부분.

CSR은 브라우저가 JS 파일을 다운로드 받고 동적으로 DOM을 생성하는 시간을 기다려야 하기 때문에 초기로딩 속도가 느리다.

하지만 초기로딩 이후에 페이지 일부를 변경할때는 서버에 해당 데이터만 요청하면 되기 때문에

이후 구동 속도는 빠르다는 장점을 가지고 있다.

또 하나,서버가 빈 뼈대만 있는 HTML을 넘겨주는 역할만 수행하면 되기 때문에

서버측에 부하가 적다.

이밖에도 클라이언트 측에서 연산,라우팅 등을 모두 직접 처리 하기 때문에 반응 속도가 빠르고 UX도 우수하다는 장점이 있다.

한편 브라우저들이 가지는 웹 크롤러는 HTML을 읽어서 검색 가능한 색인을 만들어내는데

웹 크롤러 봇 입장에서는 본 HTML은 이렇게 텅텅 비어있다.

(05:13)

검색엔진이 색인을 할만한 콘텐츠가 존재하지 않는 다는 것이다.

이 때문에 CSR은 검색엔진 최적화에 불리하다는 치명적인 단점이 있다.

열심히 서비스를 만들었는데 검색사이트에 노출되지 않는 다면 매우 슬플 일이다.

물론 남다르게 똑똑한 구글의 크롤러 봇은 자바스크립트를 실행할 줄 아니까, CSR 웹 크롤링도 가능하다고 하는데

(05:42)

하지만 아직 완벽한 단계가 아니기도하고 구글 측에서도 여전히 크롤러 봇이 JS를 실행하기전에

로봇이 JS 실행하기전에 빠르게 끌어올리는 할 수 있도록 자바 스크립트를 실행할 수 없는 다른 크롤러 봇들을 위해서 SSR 보려 해 보라는 말을 더 붙이고 있다.

그렇다면 이제 SSR에 대해서 알아보자.

(06:25)

유저가 웹사이트에 방문하면 브라우저에서 서버로 콘텐츠를 요청. 서버에서는 즉시 페이지에 필요한 데이터를 얻어와 모두 삽입 하고 css 까지 모두 적용해서 렌더링 준비를 마친 html,js code를 브라우저에 응답으로 전달. 브라우저에서는 바로 전달 받은 페이지를 띄우고. 이어 브라우저가 js code를 다운로드 하고 html에 js 로직을 연결한다

먼저 서버에서 렌더링 준비를 마친 HTML을 브라우저의 응답으로 전달한다는 부분인데

모든 데이터가 이미 HTML에 담겨진 채로 브라우저에 전달되기 때문에 검색엔진 최적화에 유리하다.

JS를 실행 할 줄 모르는 크롤러 봇도 무리 없이 HTML을 읽을 수 있다.

또 하나, 자바스크립트 코드를 다운로드 받고 실행하기 전에 사용자가 화면을 볼 수 있다는 점이다.

JS 다운로드를 기다려야했던 CSR보다 빠를 수 밖에 없다.

하지만 동시에 이것이 치명적인 단점이 되기도 하는데

이 시점에는 사용자가 버튼을 클릭 하거나 이동하려고 해도 아무런 반응이 없을 수 있다.

interaction(상호작용) 가능한 page 처럼 보이지만, 그저 내용과 스타일이 입혀진 껍데기에 불과하고, 실제로 클라이언트 측 JS가 실행되고 이벤트 핸들러가 첨부되어서 JS로직이 모두 연결될때 까지 사용자 입력에 응답할 수 없기 때문이다.사용자 입장에서는 뭔가 보여서 눌렀는데.

사용자 입장에서는 뭔가 보여서 눌렀는데 아무런 반응이 없다면 굉장히 어이 없을 것이다.

(07:24)

이렇게 SSR 안에는 TTV(Time To View)와 TTI(Time To Interact)간에 시간 간격이 존재한다는 것이 단점이다.

(07:31)

반면에 CSR은 JS가 동적으로 DOM을 생성하기 때문에 HTML은 JS 로직이 모두 완전히 연결된

상태라 사용자가 보는 시점과 이용할 수 있는 시점이 동일하다.

(08:21)

그렇다면 현재 대부분의 웹들이 사용하고 있는 CSR의 단점을 보완할 수 있는 방법은 없을까?

(08:37)

code splitting, tree-shaking,chunk 분리를 통해 JS bundle을 줄여서 초기 DOM 생성 속도를 줄이면 초기 로딩 속도를 개선할 수 있다.

(08:50)

Pren-rendering을 통해 SEO를 개선할 수 있는데 라이브러리나 웹팩 플러그인을 통해

각 페이지에 대한 HTML 파일을 미리 생성 해둔 뒤 서버에서 요청자는 자가 만약 크롤러라면 사전에 렌더링 된 HTML 버전 페이지를 보여 주는 방식을 통해 개선할 수 있다.

CSR을 사용하고 있는 SPA에 SSR이나 SSG를 도입하는 것도 방법인데

실제로 CSR의 단점을 상당 부분 보완할 수 있다.

그렇다면 CSR 앱에 SSR/SSG를 어떻게 도입할 수 있는지 방법을 알아보자.

(09:18)

1.먼저 프레임워크없이 도입하는 방법이다.

우선 프론트엔드 개발자에게 상대적으로 친숙한 Express.js로 별도의 서버를 직접 운영하는 방법이 있다.

타입스크립트 설정이 걱정된다면 기본적으로 타입스크립트를 지원하는 NestJS를 사용할 수도 있다.

하지만 이 방법들은 서버 환경 구성이나 빌드 등의 작업이 생소한 프론트엔드 개발자에게는 복잡하고 헷갈리는 부분이 많아서 다소 진입장벽이 있다. 이를 위해서 SPA에서

보다 쉽게 SSR이나 SSG를 적용할 수 있도록 해주는 프레임워크들이 있다.

먼저 Next.js는 리액트 SSR이나 SSG를 사용할 수 있게 해주는 프레임워크로

페이지의 성격 별로 SSR을 사용할 것인지 미리 정해 주는 것도 가능하다.

(10:06)

Gatsby는 SSG에 최적화,다양한 플러그인이 특징이다.

CSR,SSR,페이지 로딩 등도 지원하고

무엇보다 굉장이 다양한 플로그인들을 제공하는 것이 장점이다.

빌드 시점에 스태틱 HTML들을 만들어 주는 것이기 때문에

페이지가 적고, 작은 서비스라면 확실히 좋은 수단이 될 수있다.

Nuxt.js는 뷰를 위한 프레임 워크인데

(10:30)

Next.js에 영감을 받아서 만들어졌다고 한다.

(10:39)

Angular 유니버셜은 앵귤러에서 SSR을 가능하게 해주는데

원래 프레임워크로 시작했지만 앵귤러4 부터는 앵귤러 자체에 포함되어 있다고 한다.

엄밀히 말하면 더 이상 프레임워크가 아니다.

이러한 프레임워크들이 CSR에 SSR이나 SSG도입을 훨씬 편하게 만들어 주는 것은 사실이지만 프레임워크를 사용하더라도, 일반 SPA, 즉 CSR 개발에 코드 복잡도는 올라간다. 또 프레임워크를 사용하면 당연히 감수해야할 부분이긴 하지만

직접 제어할수 없는 블랙박스 영억도 존재한다는 것이다.

이렇게 CSR에 SSR 혹은 SSG를 도입하는 방법을 알아보았다.

(11:19)

이렇게 초기 렌더링 방식으로 SSR을 사용하고 그 이후에는 CSR을 사용하는 앱이나

그 렌더링 방식을 부르는 용어도 있다.

(11:30)

Isomorphic App은 서버와 클라이언트에서 동일한 코드가 동작하는 어플리케이션이라는 의미로 해석할 수 있다.

클라이언트와 서버가 모두 같은 코드로 돌아가기 때문에

(11:41)

예상과는 다른 결과를 마주할 가능성도 있지만 초기 로딩속도와 SEO를 해결하면서도

CSR의 장점을 그대로 가져갈수 있는 좋은 대안이 되기 때문에 최근 많이 사용하고 있는 추세이다.

(11:50)

CSR도 단점이 있고 SSR도 단점이 있다.

(11:57)

그리고 그것을 보완하려고 조합해 사용해도 단점이 있다.

그렇다면 대체 어떤 방식을 사용하는 것이 좋을까?

정답은 서비스 성격에 따라 달라진다. 만약 사용자와의 상호작용이 많고

대부분 개인정보 데이터를 기준으로 구성되는 서비스라면

검색에 상위노출되는 것보다 오히려 고객의 데이터를 보호하는 것이 더 중요할 수 있다.

모든 서비스에 SEO가 필요하지는 않다는 의미이다.

이런 서비스의 경우 SSR보다 CSR이 더 적합하다.

(12:07)

만약 회사 홈페이지이기 때문에 상위노출이 되어야하고 누구에게나 동일한 내용을

노출 하고 있다면 그리고 만약 그 페이지 데이터가 자주 바뀐다면 SSR이 더 적합할 것이고

내용을 업데이트 하는 일이 거의 없다면 SSG가 더 적합할 것이다.

만약 사용자에 따라 페이지 내용도 달라지고 빠른 인터랙션도 중요하고 검색엔진 최적화도 포기할 수 없다면 그때는 유니버셜 렌더링을 고려해보면 좋을 것이다.

(12:48)

html에서 이미지를 보는 방법은 두 가지가 있다.

1.이미 렌더링된 이미지

2.클릭 시 다운로드

CODE가 있는데, 사이트 내에서 "공통"으로 뽑기 위해 테이블 자체를 둔 것이다.

CODE를 보고 상품관리에 등록된 거구나 등 유추해야 한다.

RID는 게시판의 몇번글에 대한 첨부파일이다.

파일 첨부는 coomon->entity->uploadfile

에서 DTO부터 먼저 만들어보자

UploadFileId

code

rid

store_filename

upload_filename

fsize

ftype

cdate

udate

이렇게 DTO를 만들고

UploadFileDAO

package com.kh.app.domain.common.dao;

import com.kh.app.domain.entity.UploadFile;

import java.util.List;
import java.util.Optional;

public interface UploadFileDAO {

  /**
   * 업로드 파일 등록 - 단건
   * @param uploadFile
   * @return 파일Id
   */
  Long addFile(UploadFile uploadFile);

  /**
   * 업로드 파일 등록 - 여러건
   * @param uploadFiles
   */
  void addFiles(List uploadFiles);

  /**
   * 업로드파일조회
   * @param code
   * @param rid
   * @return
   */
  List findFilesByCodeWithRid(String code,Long rid);

  /**
   * 첨부파일조회
   * @param uploadfileId
   * @return
   */
  Optional findFileByUploadFileId(Long uploadfileId);


  /**
   * 첨부파일 삭제 by uplaodfileId
   * @param uploadfileId 첨부파일아이디
   * @return 삭제한 레코드수
   */
  int deleteFileByUploadFildId(Long uploadfileId);

  /**
   * 첨부파일 삭제 By code, rid
   * @param code 첨부파일 분류코드
   * @param rid 첨부파일아이디
   * @return 삭제한 레코드수
   */
  int deleteFileByCodeWithRid(String code, Long rid);
}
package com.kh.app.domain.common.dao;

import com.kh.app.domain.entity.UploadFile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.*;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Repository
@RequiredArgsConstructor
public class UploadFileDAOImpl implements UploadFileDAO{

  private final NamedParameterJdbcTemplate template;

  //업로드파일 등록-단건
  @Override
  public Long addFile(UploadFile uploadFile) {

    StringBuffer sql = makeAddFileSql();
    SqlParameterSource param = new BeanPropertySqlParameterSource(UploadFile.class);
    KeyHolder keyHolder = new GeneratedKeyHolder();
    template.update(sql.toString(),param,keyHolder,new String[]{"uploadfile_id"});

    return keyHolder.getKey().longValue();
  }

  //업로드파일 등록-여러건
  @Override
  public void addFiles(List uploadFiles) {

    StringBuffer sql = makeAddFileSql();
    if(uploadFiles.size() == 1){
      SqlParameterSource param = new BeanPropertySqlParameterSource(uploadFiles.get(0));
      template.update(sql.toString(),param);
    }else {
      SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(uploadFiles);
      //배치 처리 : 여러건의 갱신작업을 한꺼번에 처리하므로 단건처리할때보다 성능이 좋다.
      template.batchUpdate(sql.toString(), params);
    }
  }

  private StringBuffer makeAddFileSql() {
    StringBuffer sql = new StringBuffer();
    sql.append("INSERT INTO uploadfile ( ");
    sql.append("  uploadfile_id, ");
    sql.append("  code, ");
    sql.append("  rid, ");
    sql.append("  store_filename, ");
    sql.append("  upload_filename, ");
    sql.append("  fsize, ");
    sql.append("  ftype ");
    sql.append(") VALUES ( ");
    sql.append("  uploadfile_uploadfile_id_seq.nextval, ");
    sql.append("  :code, ");
    sql.append("  :rid, ");
    sql.append("  :store_filename, ");
    sql.append("  :upload_filename, ");
    sql.append("  :fsize, ");
    sql.append("  :ftype ");
    sql.append(") ");
    return sql;
  }

  //조회
  @Override
  public List findFilesByCodeWithRid(String code, Long rid) {
    StringBuffer sql = new StringBuffer();

    sql.append("SELECT  ");
    sql.append("   uploadfile_id, ");
    sql.append("   code, ");
    sql.append("   rid,  ");
    sql.append("   store_filename, ");
    sql.append("   upload_filename,  ");
    sql.append("   fsize,  ");
    sql.append("   ftype,  ");
    sql.append("   cdate,  ");
    sql.append("   udate ");
    sql.append("  FROM  uploadfile  ");
    sql.append(" WHERE CODE = :code  ");
    sql.append("   AND RID = :rid  ");

    return template.query(
        sql.toString(),
        Map.of("code",code,"rid",rid),
        BeanPropertyRowMapper.newInstance(UploadFile.class));
  }

  //첨부파일 조회
  @Override
  public Optional findFileByUploadFileId(Long uploadfileId) {
    StringBuffer sql = new StringBuffer();
    sql.append(" select * ");
    sql.append("  from uploadfile ");
    sql.append(" where uploadfile_id = :uploadfile_id ");

    UploadFile uploadFile = null;
    try {
      Map param = Map.of("uploadfile_id", uploadfileId);
      uploadFile = template.queryForObject(sql.toString(),param,BeanPropertyRowMapper.newInstance(UploadFile.class));
      return Optional.of(uploadFile);
    }catch (EmptyResultDataAccessException e){
      return Optional.empty();
    }
  }

  // 첨부파일 삭제 by uplaodfileId
  @Override
  public int deleteFileByUploadFildId(Long uploadfileId) {
    StringBuffer sql = new StringBuffer();
    sql.append("delete from uploadfile ");
    sql.append(" where uploadfile_id = :uploadfile_id ");

    return template.update(sql.toString(), Map.of("uploadFile_id",uploadfileId));
  }

  // 첨부파일 삭제 by code, rid
  @Override
  public int deleteFileByCodeWithRid(String code, Long rid) {
    StringBuffer sql = new StringBuffer();
    sql.append("delete from uploadfile ");
    sql.append(" where code = :code ");
    sql.append("   and rid = :rid ");

    return template.update(sql.toString(),Map.of("code",code,"rid",rid));
  }
}

SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(uploadFiles);는 uploadfile의 정보를 배열로 담은 것이다.

template.batchUpdate(sql.toString(), params);이건 배열에 담긴 걸 한 꺼번에 처리한다는 뜻이다.

배치처리란 insert문 여러 개를 한 꺼번에 쏘는 것이다.

이번엔 Test를 할 차례다.

ctrl+shift+T로 구조를 똑같게 테스트 환경을 만들 수 있다

@SpringBootTest

UploadDAOImplTest {
  @Autowired
  private UploadFileDAO uploadFileDAO
    
 @Test
 @Displayname("단건 첨부")   
  
}

IOC는 개발자가 직접 객체를 생성하지 않고, 프레임워크가 직접 생성하는 객체다.

DI는 private UploadFileDAO uploadFileDAO즉 DAO에 담긴 객체를 내게 달라는 뜻이다.

@RequiredArgsConstrutor는

final 생성자를 재료로 삼아서, 매개변수를 만들어 준다.

그렇게 되면 객체 연관관계 , 즉 sql의 pk,fk와 같이 app같에도 객체와 객체사이 참조가 되버린다.

여기선 uploadFileDAOImpl과 NamedParameterJDBCTemplate이 그 관계다.

insert into code (code_id,decode,pcode_id,useyn) values('F01','첨부파일',null,'Y');
insert into code (code_id,decode,pcode_id,useyn) values('F010301','상품관리_일반','F01','Y');
insert into code (code_id,decode,pcode_id,useyn) values('F010302','상품관리_이미지','F01','Y');

F01은 파일 첨부다.

스프링프레임이 관리하는 객체를 Bean이라고 한다.

이제 SaveForm에서

private List<MultipartFile> attachFiles; // 일반파일

private List<MultipartFile> imageFiles; // 이미지파일 이렇게 해서 이미지,파일을 받을 수 있다.

단건으로 할려면

MulipartFile attachFile로 하면 됨.

그럼 saveform요청메세지 body에 담겨져 온다.

multipartFileTouploadFile

여기서 AttachfileType aa = AttachFileType.F010301

로 해서 이넘 타입의 상수 값을 가질 수 있다 .

여기서 aa앞에 있는 AttachfileType의 값만 소환 가능.

Enum은 한정된 값을 정한 타입이다. ex)요일,성별 등 정해진 값.

@Transaction은 논리적 최소 단위다 2 or not 즉 2개의 로직이 실행되지않으면 아예 실행안되는 것이다.

<div><label for="">일반첨부</label><input type="file"></div>

여기서 파일 여러 개 추가 할려면

<div><label for="">일반첨부</label><input type="file" multiple></div>

이렇게 하면 된다.

 

'HTTP 웹 기본 지식' 카테고리의 다른 글

네트워크 상에서 데이터의 이동 이해하기  (0) 2023.05.29
HTTP 1.1/2.0/3.0  (0) 2023.04.21
TCP/UDP  (0) 2023.04.20
IP(인터넷 프로토콜)  (0) 2023.04.13
인터넷에서 컴퓨터 둘은 어떻게 통신할까?  (0) 2023.04.08

+ Recent posts