<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>marha.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 26 Feb 2025 12:25:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>marha.log</title>
            <url>https://velog.velcdn.com/images/marha-hwang/profile/87855ef5-ae2f-412f-929e-c0090d962e6a/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. marha.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/marha-hwang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[SwiftUI] @State와 @Binding 이해하기]]></title>
            <link>https://velog.io/@marha-hwang/SwiftUI-State%EC%99%80-Binding-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@marha-hwang/SwiftUI-State%EC%99%80-Binding-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 26 Feb 2025 12:25:24 GMT</pubDate>
            <description><![CDATA[<h2 id="state-와-binding을-사용하는-이유는-무엇일까">@State 와 @Binding을 사용하는 이유는 무엇일까?</h2>
<ul>
<li>데이터의 변화에 따른 뷰 업데이트를 위해 사용한다.</li>
<li>아래 코드를 보면 BindingView라는 커스텀뷰에서는 Counter라는 인스턴스를 초기화 과정에서 주입받는다
그리고 부모뷰에서 버튼을 통해 counter의 값을 증가 시켰을때 출력값은 정상적으로 증가하지만 뷰는 업데이트 되지 않는 현상이 발생한다.</li>
</ul>
<aside>

<p>부모뷰에서 Counter클래스를 사용한 이유는?</p>
<ul>
<li>struct는 값타입이므로 Immutable하다. 따라서 View구조체도 Immutable하므로,
값을 증가시키는 로직을 @State를 사용하지 않고 구현하기 위해 참조타입인 Counter을 통해 내부의 값을 증가시키는 방법을 사용하였다.</li>
</ul>
</aside>

<pre><code class="language-swift">import Foundation
import SwiftUI

class Counter{
    var count = 1
}

struct StateBinding:View {

    private var counter = Counter()

    var body: some View {

        BindingView(counter: counter)

        Button(&quot;Add Value&quot;){
            counter.count += 1
            print(counter.count)
        }
    }
}

struct BindingView:View {

    private var counter:Counter
    init(counter: Counter) {
        self.counter = counter
    }

    var body: some View {
        Text(String(counter.count))
    }
}
</code></pre>
<h2 id="데이터-변화에-따른-뷰의-업데이트를-어떻게-구현해야-할까">데이터 변화에 따른 뷰의 업데이트를 어떻게 구현해야 할까?</h2>
<ul>
<li>일반적인 변수로는 데이터의 변화에 따른 뷰의 업데이트를 구현할 수 없다. 그렇기 때문에 사용하는 것이 @State와 @Binding이다.</li>
<li>상태 변화에 따라 UI에 반영하기 위한 데이터는 @State로 선언한다.</li>
<li>자식뷰에서 부모뷰의 @State변수를 전달받아 사용하고 싶다면 @Binding 변수를 선언하여 사용한다.
@Binding변수에는 자동으로 이니셜라이저가 구현된다.</li>
</ul>
<pre><code class="language-swift">import Foundation
import SwiftUI

struct StateBinding:View {

    @State private var count = 1

    var body: some View {

        BindingView(count: $count)

        Button(&quot;Add Value&quot;){
            count += 1
            print(count)
        }
    }
}

struct BindingView:View {

    @Binding var count:Int

    var body: some View {
        Text(String(count))
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Combine] sink, assign 의 차이점]]></title>
            <link>https://velog.io/@marha-hwang/Combine-sink-assign-%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
            <guid>https://velog.io/@marha-hwang/Combine-sink-assign-%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</guid>
            <pubDate>Sat, 01 Feb 2025 08:10:24 GMT</pubDate>
            <description><![CDATA[<p>공통점 :</p>
<ul>
<li>sink와 assign모두 값을 구독하고 이를 처리하기 위한 방법이다.</li>
</ul>
<p>차이점 : </p>
<ul>
<li>sink : 값을 받아 처리하는 클로저를 전달받아 해당 값을 통한 로직 수행</li>
<li>assign : 값을 전달받아 특정 객체의 프로퍼티에 할당시킴</li>
</ul>
<h2 id="sink의-정의">sink의 정의</h2>
<p><img src="https://velog.velcdn.com/images/marha-hwang/post/8e80a4c4-638a-40fd-8770-d0cf0eb2baa8/image.png" alt=""></p>
<ul>
<li>subscriber을 직접 구현 할 필요없이 해당 publisher의 타입을 준수하는 subscriber을 반환해준다.</li>
<li>AnyCancellable프로토콜을 준수하는 subscriber를 반환하기 때문에 구독 취소를 할 수 있다.</li>
</ul>
<h3 id="sink예제">sink예제</h3>
<pre><code class="language-swift">let myRange = (0...3)
cancellable = myRange.publisher
    .sink(receiveCompletion: { print (&quot;completion: \($0)&quot;) },
          receiveValue: { print (&quot;value: \($0)&quot;) })

// Prints:
//  value: 0
//  value: 1
//  value: 2
//  value: 3
//  completion: finished</code></pre>
<h2 id="assignto의-정의">assign(to:)의 정의</h2>
<p><img src="https://velog.velcdn.com/images/marha-hwang/post/25c003c4-51b0-4f84-b888-ab431e0a9bd1/image.png" alt=""></p>
<ul>
<li>publisher로 부터 방출받은 값을 @Published가 붙은 인스턴스에서 재방출하기 위해 사용하는 연산자이다.</li>
<li>@Published가 붙은 인스턴스의 생명주기에 따라 subscription이 관리 되기 때문에 AnyCancellable인스턴스를 반환하지 않는다.</li>
</ul>
<h3 id="assignto예제">assign(to:)예제</h3>
<ul>
<li>Just를 통해 100이란 값을 방출하면 MyModel인스턴스 id에 값을 전달하는 코드</li>
</ul>
<pre><code class="language-swift">    class MyModel: ObservableObject {
        @Published var id: Int = 0
    }
    let model2 = MyModel()
    Just(100).assign(to: &amp;model2.$id)</code></pre>
<h2 id="assigntoon">assign(to:on:)</h2>
<p><img src="https://velog.velcdn.com/images/marha-hwang/post/41d2197f-ba01-463c-bc6f-5ce99db8a01f/image.png" alt=""></p>
<ul>
<li>publisher로 부터 방출받은 값을 특정 객체의 프로터티에 할당한다.</li>
<li>keyPath는 on의 객체에서 프로퍼티를 특정시키기 위한 인풋값이다.</li>
<li>AnyCancellable인스턴스를 반환하므로 프로퍼티에 값이 자동할당 되는 것을 중지하고 싶다면 cancell()함수를 호출하면 된다.</li>
</ul>
<h3 id="assigntoon-예제">assign(to:on:) 예제</h3>
<pre><code class="language-swift">class MyClass {
    var anInt: Int = 0 {
        didSet {
            print(&quot;anInt was set to: \(anInt)&quot;, terminator: &quot;; &quot;)
        }
    }
}

var myObject = MyClass()
let myRange = (0...2)
cancellable = myRange.publisher
    .assign(to: \.anInt, on: myObject)

// Prints: &quot;anInt was set to: 0; anInt was set to: 1; anInt was set to: 2&quot;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Combine] Subject에 대해 알아보기]]></title>
            <link>https://velog.io/@marha-hwang/Combine-Subject%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@marha-hwang/Combine-Subject%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Sat, 01 Feb 2025 07:59:43 GMT</pubDate>
            <description><![CDATA[<h2 id="subject를-사용하는-이유">Subject를 사용하는 이유</h2>
<p>내가 처음 Combine을 공부할 때 Publisher은 무조건 값을 소유 해야 하고 해당 값이 어떤 이벤트에 의해서 변화 할 때 subscriber에 값을 방출하는 것인 줄 잘못 알고 있었다.</p>
<p>하지만 combine의 값 방출 시점은 값의 변화가 아닌 이벤트 발생 시점과 더 가깝다는 사실을 알게 되었다.</p>
<p>만약 이벤트 발생시점을 외부에서 호출을 통해 제어하고 싶다면 어떻게 해야할까?</p>
<p>이런 경우에 사용 할 수 있는 것이 subject이다.</p>
<h2 id="subject프로토콜의-정의">Subject프로토콜의 정의</h2>
<aside>

<p><strong>A publisher that exposes a method for outside callers to publish elements.</strong>
외부 호출자를 통해 값을 방출시키기 위한 함수를 노출시키는 puslisher이다.</p>
<p><strong>A subject is a publisher that you can use to ”inject” values into a stream, by calling its <a href="https://developer.apple.com/documentation/combine/subject/send(_:)"><code>send(_:)</code></a> method. This can be useful for adapting existing imperative code to the Combine model.</strong>
subject는 send메서드를 호출함으로써  스트림에 값을 삽입할 수 있는 publisher이다. 
이것은 기존 명령형 코드를 combine모델에 적용하는데 유용할 수 있다.</p>
</aside>

<h2 id="subject프로토콜-구현체">Subject프로토콜 구현체</h2>
<ul>
<li><p>PassthroughSubject
하위 subscriber에게 브로트캐스트 방식으로 값을 전파하는 publisher이다.</p>
</li>
<li><p>CurrentValueSubject
내부에 값을 가지고 있고 내부 값이 변화하면 하위 subscriber들에게 값을 전파한다.</p>
</li>
</ul>
<h2 id="두-구현체의-차이는-무엇일까">두 구현체의 차이는 무엇일까?</h2>
<p>PassthroughSubject는 send메서드를 통해 들어온 값은 단순히 방출시키는 역활만 한다면</p>
<p>CurrentValueSubject는 send메서드를 통해 들어온 값을 내부에 저장하고 저장된 값을 방출시키는 과정을 거친다.</p>
<h2 id="구현예제">구현예제</h2>
<ul>
<li><p>출력결과를 보면 두가지 Subject모두 sub1을 생성하고 .finished값을 방출한다.
이때 CurrentValueSubject는 값을 소유하기 때문에 sub1을 생성한 직후 subject에 저장된 초기값을 바로 방출하지만 PassThroughSubject는 completion결과만 출력되는 것을 볼수있다.</p>
</li>
<li><p>PassThroughSubject예제</p>
</li>
</ul>
<pre><code class="language-swift">    func callPassthrough(){
        let passthroughSubject = PassthroughSubject&lt;String, Never&gt;()

        let sub1 = passthroughSubject
            .sink(receiveCompletion: { print(&quot;1 번째 sink completion: \($0)&quot;) },
                  receiveValue: { print(&quot;1 번째 sink value: \($0)&quot;) })

        passthroughSubject.send(completion: .finished)

        let sub2 = passthroughSubject
            .sink(receiveCompletion: { print(&quot;2 번째 sink completion: \($0)&quot;) },
                  receiveValue: { print(&quot;2 번째 sink value: \($0)&quot;) })

        // 현재 Subscriber들에게 모두 보냄
        passthroughSubject.send(&quot;두번째 값&quot;)

    }</code></pre>
<aside>

<p>출력결과</p>
<p>1 번째 sink completion: finished
2 번째 sink completion: finished</p>
</aside>

<ul>
<li>CurrentValueSubject</li>
</ul>
<pre><code class="language-swift">    func callCurrentValue(){
        let currentValueSubject = CurrentValueSubject&lt;String, Never&gt;(&quot;첫번째 값&quot;)

        let sub1 = currentValueSubject
            .sink(receiveCompletion: { print(&quot;1 번째 sink completion: \($0)&quot;) },
                  receiveValue: { print(&quot;1 번째 sink value: \($0)&quot;) })

        currentValueSubject.send(completion: .finished)

        let sub2 = currentValueSubject
            .sink(receiveCompletion: { print(&quot;2 번째 sink completion: \($0)&quot;) },
                  receiveValue: { print(&quot;2 번째 sink value: \($0)&quot;) })

        // 현재 Subscriber들에게 모두 보냄
        currentValueSubject.send(&quot;두번째 값&quot;)

        print(currentValueSubject.value)
    }</code></pre>
<aside>

<p>출력값</p>
<p>1 번째 sink value: 첫번째 값
1 번째 sink completion: finished
2 번째 sink completion: finished
첫번째 값</p>
</aside>]]></description>
        </item>
        <item>
            <title><![CDATA[[SwiftUI] ForEach]]></title>
            <link>https://velog.io/@marha-hwang/SwiftUI-ForEach</link>
            <guid>https://velog.io/@marha-hwang/SwiftUI-ForEach</guid>
            <pubDate>Sat, 18 Jan 2025 09:50:21 GMT</pubDate>
            <description><![CDATA[<h2 id="foreach를-사용하는-이유는-무엇일까">ForEach를 사용하는 이유는 무엇일까?</h2>
<p>UIKit같은 경우는 swift문법에서 지원하는 for문을 통해 반복되는 View를 구현할 수 있었다.</p>
<p>하지만 SwiftUI를 통해 View를 구현할 때는 for문을 사용할 수 없기 때문에 ForEach를 사용해야 한다.</p>
<h2 id="swiftui는-왜-for문을-사용할-수-없을까">SwiftUI는 왜 for문을 사용할 수 없을까?</h2>
<p><strong>SwiftUI를 한마디로 정의하면 선언적 UI를 구현하기 위한 프레임워크이다.</strong></p>
<p>자세히 풀어 설명하면 View를 선언하여 생성하면 View는  상태에 따라 알아서 변화해야 한다는 것을 의미한다.</p>
<h2 id="그렇다면-상태에-따라-변화하는-것과-foreach사이에는-무슨-관계가-있을까">그렇다면 상태에 따라 변화하는 것과 ForEach사이에는 무슨 관계가 있을까?</h2>
<p>만약 어떤 View의 상태가 변화한다면 이에 대해 View를 변화시켜야 한다. 그리고 이를 위해서는 SwiftUI의 뷰 시스템에서 상태변화에 따른 처리를 하기 위해 뷰를 고유하게 식별할 수 있는 방법이 필요하다.</p>
<p>정리하자면 ForEach는 View들이 고유 식별자(id)를 가지도록 돕는 역할을 함으로써 상태 변화에 따라 View가 자동으로 변화될 수 있도록 한다.</p>
<h2 id="foreach의-정의">ForEach의 정의</h2>
<p><img src="https://velog.velcdn.com/images/marha-hwang/post/bca8426d-c6bb-4e52-8c80-0530e14a15cf/image.png" alt=""></p>
<p><code>RandomAccessCollection</code>: <strong>Swift의 컬렉션 타입</strong> 중 하나로, <strong>인덱스를 통해 임의로 접근 가능</strong>한 컬렉션을 정의하는 프로토콜. </p>
<p><code>Hashable</code> : Swift에서 중요한 프로토콜 중 하나로, <strong>객체를 고유하게 식별</strong>할 수 있는 <strong>해시 값</strong>을 생성할 수 있도록 함. 이 프로토콜은 주로 Set, Dictionary와 같은 컬렉션에서 <strong>객체를 고유하게 식별하고 저장</strong>하기 위해 사용</p>
<h2 id="foreach구현예제">ForEach구현예제</h2>
<ul>
<li>categoryList배열을 사용하여 List의 각 Section을 구성하고, menuList를 사용하여 각 Section내부에서 리스트 요소를 추가하는 예제이다.</li>
<li>forEach를 사용할 때는 데이터를 구분하기 위한 id값이 필요하다. 따라서 Menu구조체 같은 경우 이를 구현하기 위해 Identifiable프로토콜을 준수하였다.</li>
<li>ForEach(menuList[i], id: .id)  에서 .id의 의미는 Menu구조체의 id프로퍼티를 식별자로 사용한다는 것을 의미한다.</li>
</ul>
<pre><code class="language-swift">struct Menu:Identifiable{
    var id:String{ name }
    let name:String
    let price:String
    let description:String
    let imageUrl:String
}

let categoryList = [&quot;인기메뉴&quot;, &quot;양념치킨&quot;, &quot;후라이드 치킨&quot;, &quot;간장치킨&quot;, &quot;파닭&quot;, &quot;스페셜 치킨&quot;]
let menuList:[[Menu]] = [ ... ]

List{
    ForEach(0..&lt;categoryList.count, id: \.self) { i in
        Section(header: Text(categoryList[i])){
            ForEach(menuList[i], id: \.id) { menu in
                MenuCardView(menu: menu, action: nil)
                    .frame(height:100)
            }
        }
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SwiftUI] GeometryReader]]></title>
            <link>https://velog.io/@marha-hwang/SwiftUI-GeometryReader</link>
            <guid>https://velog.io/@marha-hwang/SwiftUI-GeometryReader</guid>
            <pubDate>Thu, 09 Jan 2025 14:49:06 GMT</pubDate>
            <description><![CDATA[<h2 id="어떤상황에서-쓰일까">어떤상황에서 쓰일까?</h2>
<p>SwiftUI는 선언형 UI라고 한다. 따라서 뷰의 위치를 하나하나 잡아줄 필요 없이 뷰를 생성함으로써 부모뷰는 자식뷰에게 위치와 크기를 제안하고 이를 통해 자식뷰는 알아서 제자리를 찾고 크기를 결정한다.</p>
<p>하지만 자식뷰는 부모뷰가 제안한 위치를 기준으로 원하는 위치를 알아서 찾아야 하는 경우가 존재한다.</p>
<p>이때 사용하는 것이 GeometryReader이다.</p>
<h2 id="geometryreader의-정의">GeometryReader의 정의</h2>
<blockquote>
<p><strong>A container view that defines its content as a function of its own size and coordinate space.
콘텐츠를 자체 크기와 좌표 공간의 함수로 정의하는 컨테이너 뷰입니다.</strong></p>
</blockquote>
<p>애플 공식문서의 설명에 따르면 Geometry는 컨테이너뷰이고 내부의 콘텐츠를 자체크기와 좌표공간을 포함하는 클로저 함수를 통해 정의한다고 한다.</p>
<p>여기서 크기와 좌표공간을 제공하기 위해 GeometryProxy라는 구조체를 사용하는데 해당 구조체의 정의는 다음과 같다</p>
<p><a href="https://developer.apple.com/documentation/swiftui/geometryproxy">GeometryProxy | Apple Developer Documentation</a></p>
<blockquote>
<p><strong>A proxy for access to the size and coordinate space (for anchor resolution) of the container view.
컨테이너 뷰(GeometryReader)의 크기와 좌표 공간(앵커 해상도)에 대한 접근을 위한 프록시입니다.</strong></p>
</blockquote>
<h2 id="예제">예제</h2>
<ul>
<li>GeometryReader은 할당가능한 모든 영역을 차지한다. 아래 예제를 보면 최상위 View는 VStack이고 Stack는 기본적으로 자식뷰의 크기만큼의 공간만 차지한다.
하지만 GeometryReader(파랑)가 모든 영역을 차지한 것을 확인 할 수 있다.</li>
</ul>
<pre><code class="language-swift">struct GeometryView: View {

    var body: some View {
        VStack{
            GeometryReader{ proxy in
                Text(&quot;Hello World~~&quot;).background(Color.yellow)
            }
            .background(Color.blue)
        }
        .background(Color.red)
        }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/marha-hwang/post/972c74cd-603d-49c5-b521-d91215d4dace/image.png" alt=""></p>
<h2 id="참조한-것">참조한 것</h2>
<p><a href="https://medium.com/hcleedev/swift-geometryreader%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C-564896c6d6e0">Swift: GeometryReader는 무엇일까?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인패턴] Adapter패턴]]></title>
            <link>https://velog.io/@marha-hwang/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-Adapter%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@marha-hwang/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-Adapter%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 27 Jun 2023 01:34:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/marha-hwang/post/e8883dbf-571a-4bd5-bae2-22d5797df56a/image.png" alt="">
클라이언트가 A클래스의 기능을 사용하기 위해서는 인터페이스A를 이용한다.
B클래스 기능을 사용하기 위해서는 인터페이스B를 이용한다.
하지만 인터페이스A를 이용하여 B클래스를 사용할 수는 없다.
따라서 클라이언트가 인터페이스A를 이용하여 B클래스를 사용하기 위해서는 별도의 어댑터 클래스가 필요하고 인터페이스A의 구현 메서드를 B클래스와 매핑시키는 방식으로 구현한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Spring 클라이언트 데이터 처리]]></title>
            <link>https://velog.io/@marha-hwang/Spring-Spring-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@marha-hwang/Spring-Spring-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Wed, 21 Jun 2023 11:17:55 GMT</pubDate>
            <description><![CDATA[<h2 id="url로-들어오는-데이터-처리">URL로 들어오는 데이터 처리</h2>
<h3 id="pathvariable">@PathVariable</h3>
<blockquote>
<p>url경로에 변수를 사용하는 경우에 사용함</p>
</blockquote>
<ul>
<li>코드예시<pre><code>@RequestMapping(&quot;/{name}&quot;)
public String printName(@PathVariable String name, Model model ) {
  model.addAttribute(&quot;name&quot;, name);
  return &quot;home&quot;;
}
</code></pre></li>
</ul>
<pre><code>
### @MatrixVariable 
&gt; “/…/name=gildong;age=19/…/ 과 같이 url에 포함된 다중 피라미터를 사용하는 경우에 사용

- dispatcher-servlet.xml에 아래와 같이 설정 추가</code></pre><annotation-driven enable-matrix-variables="true"/>
```

<ul>
<li>코드예시<pre><code>//url에 다중피라미터를 사용하는 경우 url=”/name=gilding;age=19”
@RequestMapping(&quot;/{user}&quot;)
public String printUser(
                      @MatrixVariable(value=&quot;name&quot;, pathVar=&quot;user&quot;) String name,
                      @MatrixVariable(value=&quot;age&quot;, pathVar=&quot;user&quot;) String age,
                      Model model) {
  System.out.println(name);
  System.out.println(age);
  return &quot;home&quot;;
}
</code></pre></li>
</ul>
<p>// Map과 함께 사용하여 value를 따로 지정하지 않고 한번에 받기 가능
@RequestMapping(&quot;/{user}&quot;)
public String printUser(
                        @MatrixVariable(pathVar=&quot;user&quot;) Map&lt;String,String&gt; param,
                        Model model) {
    System.out.println(param.get(&quot;name&quot;));
    System.out.println(param.get(&quot;age&quot;));
    return &quot;home&quot;;
}</p>
<pre><code>
### @RequestParam 
&gt; “/user?name=gildong” 와 같이 url경로에 “?”로 구분된 피라미터를 처리하기 위해 사용하는 방식

- 코드예시</code></pre><p>//url에 포함된 피라미터를 처리하는 가장 일반적인 방식 url= &quot;/user?name=gildong&quot;
@RequestMapping(&quot;/user&quot;)
public String Home(@RequestParam String name, Model model) {
    System.out.println(name);
    return &quot;home&quot;;
}</p>
<pre><code>### @ModelAttribute 
&gt; DTO객체를 생성하여 url쿼리로 넘어온 피라미터를 생성된 DTO객체에 자동으로 바인딩후 model에 추가함, jsp에서는 생성된 객체를 getter를 이용하여 사용

- 코드예시</code></pre><p>//url피라미터를 model에 DTO객체로 전달 url=&quot;/user?name=gildong&amp;age=19&quot;
@RequestMapping(&quot;/user&quot;)
// @ModelAttribute의 &quot;user&quot;속성은 model에 전달된 객체명임 따라서 jsp에서 사용시 ${user.getName()}과 같이 사용한다
public String Home(@ModelAttribute(&quot;user&quot;) HomeDTO user, Model model) {
        System.out.println(user.getName());
        System.out.println(user.getAge());
        return &quot;home&quot;;
}</p>
<pre><code>
## HTTP body로 들어오는 데이터 처리
&gt; http body데이터의 변환은 HttpMessageConverter을 이용하고, HttpMessageConverter은 변환할 데이터가 json, xml, string인지에 따라 여러 구현된 클래스가 존재한다.
http 헤더의 content-type 설정에 따라 변환을 진행할 HttpMessageConverter종류가 달라진다 이를 통하여 변환될 데이터의 종류를 지정 가능하다
예를들어 body의 내용을 json으로 변환하기 위해서는 content-type를 application/json으로 설정하면 MappingJacksonHttpMessageConverter클래스를 이용하여 json형태로 데이터를 변환한다.

### @RequestBody 
&gt; http request의 body내용을 HttpMessageConverter을 이용하여 자바 객체로 변환
- MappingJacksonHttpMessageConverter을 이용하면 json데이터를 변환가능

### @ResponseBody 
&gt; http response의 body에 HttpMessageConverter을 이용하여 데이터 세팅 
- MappingJacksonHttpMessageConverter을 이용하면 json데이터를 변환가능

- json형태의 데이터를 Map또는 DTO객체로 변환하기 위해 jackson라이브러리 pom.xml에 추가
&gt; MappingJacksonHttpMessageConverter클래스 추가됨
</code></pre><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<pre><code>    &lt;dependency&gt;
        &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
        &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt;
        &lt;version&gt;2.14.2&lt;/version&gt;
    &lt;/dependency&gt;    
    &lt;!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.codehaus.jackson&lt;/groupId&gt;
        &lt;artifactId&gt;jackson-mapper-asl&lt;/artifactId&gt;
        &lt;version&gt;1.9.13&lt;/version&gt;
    &lt;/dependency&gt;</code></pre><pre><code>
- 코드예시</code></pre><p>//http body내용을 객체로 받고 body 내용 세팅하기
@RequestMapping(&quot;/user&quot;)
public @ResponseBody HomeDTO Home(@RequestBody HomeDTO user) {
    HomeDTO dto = new HomeDTO();
    dto.setName(user.getName());
    dto.setAge(user.getAge());
    return dto;
}</p>
<p>```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 예외처리]]></title>
            <link>https://velog.io/@marha-hwang/JAVA-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@marha-hwang/JAVA-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Thu, 15 Jun 2023 11:12:18 GMT</pubDate>
            <description><![CDATA[<h2 id="예외를-처리하는-두가지-추상-클래스">예외를 처리하는 두가지 추상 클래스</h2>
<ul>
<li>Exception : 컴파일시에 발생하는 에러를 처리할 때 사용</li>
<li>RuntimeException : 런타임시에 발생하는 에러를 처리할 때 사용<blockquote>
<p>Exception을 구현한 경우에는 예외 처리를 try catch 또는 throws를 통해 필수적으로 해야 하고,
RuntimeException을 구현한 경우에는 예외 처리코드를 작성하지 않아도 되지만 이러한 경우 &quot;예외 발생 함수를 호출한 최상위 함수(main함수)&quot;까지 바로 종료되고 예외처리가 진행된다 </p>
<br>
</blockquote>
</li>
</ul>
<h2 id="예외처리-구현방법">예외처리 구현방법</h2>
<h3 id="try-catch구문을-이용한-예외-처리와-함수-옆-throws키워드를-사용한-예외처리">try catch구문을 이용한 예외 처리와 함수 옆 throws키워드를 사용한 예외처리</h3>
<p><strong>차이점 : 예외 처리를 실행 하는 함수가 달라진다.</strong></p>
<blockquote>
<p><strong>try catch : 예외가 발생한 함수에서 예외처리</strong></p>
</blockquote>
<ul>
<li>예외 발생시 cahch문으로 흐름이 넘어가고 해당 함수의 나머지 코드도 모두 실행된다. 따라서 아래 코드에서 divde함수는 int형을 return해야 하기 때문에 int형을 return하지 않으면 에러가 발생한다.</li>
</ul>
<blockquote>
<p><strong>함수옆 throws : 예외가 발생한 함수를 호출한 함수에서 예외 처리</strong> </p>
</blockquote>
<ul>
<li>예외가 발생한 함수를 바로 종료시키고 해당 함수를 호출한 대상에게 예외 처리를 넘긴다. </li>
</ul>
<h2 id="예제-코드">예제 코드</h2>
<blockquote>
<p> 0으로 나누면 DivideException예외처리를 하는 코드</p>
</blockquote>
<ul>
<li>Exception을 구현한 클래스(기본형)<pre><code>public class DivideException extends Exception{
}</code></pre></li>
<li>try catch로 예외처리를 하는 코드</li>
</ul>
<pre><code>public class Main {

    public static void main(String[] args) {
        divide(5,0);
    }

    public static int divide(int a, int b){
        try {
            if(b == 0) {
                throw new DivideException();
            }
        }catch(DivideException e) {
            e.printStackTrace();
            return -1;
        }
        return a/b;
    }
}</code></pre><ul>
<li><p>throws로 예외처리를 하는 코드</p>
<pre><code>public class Main {

  public static void main(String[] args) {
      try {
          divide(5,0);
      } catch (DivideException e) {
          e.printStackTrace();
      }
  }

  public static int divide(int a, int b) throws DivideException{
      if(b == 0) {
          throw new DivideException();
      }

      return a/b;
  }
}</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Spring 인터셉터]]></title>
            <link>https://velog.io/@marha-hwang/Spring-Spring-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0</link>
            <guid>https://velog.io/@marha-hwang/Spring-Spring-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0</guid>
            <pubDate>Wed, 14 Jun 2023 14:13:47 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h3 id="인터셉터란">인터셉터란?</h3>
<p>디스패처 서블릿과 컨트롤러 사이에 위치하여 컨트롤러로 가는 요청, 컨트롤러에서 오는 응답을 가로채어 특정 작업을 처리한다.
여기서 특정 작업이란 “url요청에 대한 log처리”, “권한체크” 와 같이 컨트롤러에서 중복하여 작성해야 하는 코드를 통해 처리되는 작업을 말한다.</p>
</blockquote>
<h3 id="handlerintercepter인터페이스">HandlerIntercepter인터페이스</h3>
<ul>
<li>인터셉터는 HandlerIntercepter인터페이스를 구현하여 사용한다
아래 3가지 함수중 필요한 함수를 작성한다.</li>
</ul>
<blockquote>
<p><strong>preHandle</strong>(HttpServletRequest request,  HttpServletResponse response, Object handler) 
  실행시점 : 디스패처 서블릿에서 컨트롤러로 요청이 전달되기 이전 실행</p>
</blockquote>
<blockquote>
<p><strong>postHandle</strong>(HttpServletRequest arg0, HttpServletResponse response, Object handler, ModelAndView modelAndView) 
  실행시점 : 컨트롤러를 호출하여 요청을 처리한 이후 실행</p>
</blockquote>
<ul>
<li>view를 생성하기전에 호출되어 model의 데이터를 참조하거나 조작가능</li>
</ul>
<blockquote>
<p><strong>afterCompletion</strong>(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
  실행시점 : View생성까지의 모든 작업을 처리한 이후 실행</p>
</blockquote>
<h3 id="인터셉터의-구현단계">인터셉터의 구현단계</h3>
<ol>
<li>HandlerIntercepter를 구현한 클래스를 작성한다.</li>
</ol>
<ul>
<li>아래 예제 코드에서는 각 함수를 호출하여 로그 찍는 과정을 구현했다</li>
</ul>
<pre><code>import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class ExampleIntercepter implements HandlerInterceptor{
    public Logger logger = LoggerFactory.getLogger(ExampleIntercepter.class);


    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception{
        logger.info(&quot;인터셉터 preHandle함수 실행&quot;);
        return true;
    }

    public void postHandle(HttpServletRequest arg0,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception{
        logger.info(&quot;인터셉터 postHandle함수 실행&quot;);
    }

    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception exception) throws Exception{
        logger.info(&quot;인터셉터 afterCompletion함수 실행&quot;);
    }
}</code></pre><ol start="2">
<li>selvlet-context.xml에 &lt; intercepters&gt;태그안에 작성한 인터페이스 클래스를 bean으로 등록한다.</li>
</ol>
<pre><code>&lt;interceptors&gt;
        &lt;beans:bean class=&quot;intercepter.ExampleIntercepter&quot;/&gt;
&lt;/interceptors&gt;</code></pre><h3 id="실행결과">실행결과</h3>
<p><img src="https://velog.velcdn.com/images/marha-hwang/post/6d482162-4b8e-4172-be2d-8f315edaa63a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Spring과 Log]]></title>
            <link>https://velog.io/@marha-hwang/Spring-Spring%EA%B3%BC-Log</link>
            <guid>https://velog.io/@marha-hwang/Spring-Spring%EA%B3%BC-Log</guid>
            <pubDate>Wed, 14 Jun 2023 13:59:09 GMT</pubDate>
            <description><![CDATA[<h3 id="systemoutprint-대신-log를-사용하는-이유는-무엇일까">System.out.print() 대신 Log를 사용하는 이유는 무엇일까?</h3>
<ul>
<li>System.out.print()에 비해 오버헤드가 적다.</li>
<li>시간, 로그레벨, 발생한 클래스등 더 자세한 정보를 알 수 있다.</li>
<li>로그 내용을 파일에 남기기 간편하다.</li>
<li>원하는 레벨의 로그만 확인가능하다.<br>

</li>
</ul>
<h3 id="로그를-구성하는-요소">로그를 구성하는 요소</h3>
<ul>
<li>logger클래스 : 로그 출력여부를 설정된 로그 레벨에 따라 결정하고 appender에 로그 정보를 전달</li>
<li>appender클래스 : 로그정보를 출력할 위치를 결정하는 클래스(파일, 콘솔, DB등등)</li>
<li>layout클래스 : 로그정보의 출력 형식을 결정(HTML형식, XML형식, 사용자 정의 형식 등등)<br>

</li>
</ul>
<h3 id="로그-레벨아래로-갈수록-로그의-레벨이-높음">로그 레벨(아래로 갈수록 로그의 레벨이 높음)</h3>
<p>  TRACE : 가장 하위레벨의 로그
DEBUG : 디버그 용도로 사용
INFO : 런타임시에 발생하는 동작을 나타낼 때 사용
WARN : 오류가 발생할 가능성이 존재하는 경우 사용
ERROR : 오류가 발생한 경우 사용
FATAL : 프로그램이 강제로 종료될 만한 오류인 경우 사용
<br></p>
<blockquote>
<p>logger의 계층구조 </p>
</blockquote>
<ul>
<li>logger는 계층구조를 가지고 모든 logger의 최상위 logger는 root logger이다. logger가 따로 지정되지 않은 경우 root logger에서 설정된 방식으로 로그를 출력한다</li>
</ul>
<h3 id="spring에서-log4j-적용">spring에서 log4j 적용</h3>
<ol start="0">
<li>pom.xml에 log4j의존성 설정이 되었는지 확인</li>
<li>src/main/resources 폴더 아래 log4j.xml 파일 생성<ol start="2">
<li>&lt; appender&gt;태그안에 &lt; layout&gt;태그를 작성하여 로그를 출력할 위치와 방식을 설정한다</li>
<li>&lt; logger&gt;태그에 logger를 추가할 패키지와 출력할 로그레벨을 설정한다</li>
<li>&lt; root&gt;태그를 통해 root logger을 설정한다.</li>
</ol>
</li>
</ol>
<blockquote>
<p>로그가 설정된 대로 출력되지 않았던 이유</p>
</blockquote>
<ul>
<li>Src/test/resource에 같은 같은 이름의 log4j.xml파일이 존재 했는데 해당 파일에서 로그레벨을 수정하니 정상적으로 출력했다. 따라서 Src/main/resource의 log4j.xml의 설정을 사용하기 위해 src/test/resource의 파일을 삭제했다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Spring 프로젝트 생성]]></title>
            <link>https://velog.io/@marha-hwang/Spring-Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@marha-hwang/Spring-Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Wed, 07 Jun 2023 11:32:21 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>문제 : STS 플러그인 설치 오류 발생 – 기존에 사용하던 이클립스에서 마켓플레이스를 통해 STS를 설치하려고 하였으나 플러그인이 기존 이클립스의 버전을 지원하지 않아 설치 오류 발생</p>
</blockquote>
<blockquote>
<p>해결 : STS설치또는 이클립스 버전 변경후 플러그인 설치(STS는 이클립스 기반의 스프링에 최적화된 IDE)
(스프링 홈페이지에서 STS3다운 최신 버전인 STS4는 legacy project생성이 불가함)
STS3다운로드 링크 - <a href="https://github.com/spring-attic/toolsuite-distribution/wiki/Spring-Tool-Suite-3">https://github.com/spring-attic/toolsuite-distribution/wiki/Spring-Tool-Suite-3</a> //자바 11이상</p>
</blockquote>
<blockquote>
<p>다음부터 주의 할 점 :  똑같이 했는데도 실패하면 버전을 의심해야 하고 그래도 안되면 해당 기능을 더 이상 지원하지 않기 때문에 오류가 뜨는 것인지 확인해볼 필요가 존재</p>
</blockquote>
<ul>
<li>ex)이클립스에 sts plug-in버전이 일치하지 않아 생긴 오류, spring버전과 tomcat버전이 일치하지 않아 생긴 오류</li>
</ul>
<h4 id="이번-포스팅에서는-spring-legacy-project를-생성하는-법을-정리하고자-함-sts3를-통해-간단하게-생성-가능하지만-spring프로젝트의-구조를-이해하고자-dynamic-web-project를-통해-spring프로젝트를-생성-해-봄">이번 포스팅에서는 spring legacy project를 생성하는 법을 정리하고자 함 STS3를 통해 간단하게 생성 가능하지만 spring프로젝트의 구조를 이해하고자 Dynamic Web Project를 통해 spring프로젝트를 생성 해 봄</h4>
<h3 id="spring-project-생성과정">Spring project 생성과정</h3>
<ol>
<li>다이나믹 웹프로젝트 생성</li>
<li>메이븐 프로젝트로 변환</li>
<li>pom.xml설정 : <project>태그 안에 dependencies작성 spring-web, spring-webmvc를 기본적으로 설정(mvnrepository에서 복사해오기)</li>
<li>pom.xml 저장 후 update project</li>
<li>web.xml 설정 : 1. ApplicationContext설정 2. 리스너 등록 3. 디스패처 서블릿 생성 및 매핑 4. UTF-8필터 설정</li>
<li>WEB-INF폴더아래 spring폴더를 새로 만들고 root-context.xml, servlet-context.xml 생성</li>
<li>실행 테스트를 위해 src폴더아래 com.spring.test패키지 생성 후 TestController, TestService클래스 작성</li>
<li>WEB-INF폴더 아래 views폴더 생성 후 hello.jsp파일 작성</li>
</ol>
<h3 id="참고사항">참고사항</h3>
<blockquote>
<ul>
<li>xml 문서의 태그 구조를 정의하기 위해서는 xsd파일이 필요한데 servlet-context.xml에서는 beans태그를 사용하고 beans태그의 xsd파일을 가져오기 위해 “xmlns:xsi”, “xsi:schemaLocation”을 사용한다  </li>
</ul>
</blockquote>
<ul>
<li>한번에 여러 태그를 사용하는 경우 중복되는 태그가 존재 할 가능성이 있는데 이런 경우를 해결하기 위해 “xmlns:context”와 같이 태그에 접두사를 생성한 후 “<a href="context:component-scan">context:component-scan</a>”와 같은 방식으로 사용한다</li>
</ul>
<p>Xml스키마 관련 참조 - <a href="https://linuxism.ustd.ip.or.kr/911">https://linuxism.ustd.ip.or.kr/911</a></p>
<h3 id="코드">코드</h3>
<pre><code>===============================================================
web.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns=&quot;http://xmlns.jcp.org/xml/ns/javaee&quot; xsi:schemaLocation=&quot;http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd&quot; id=&quot;WebApp_ID&quot; version=&quot;4.0&quot;&gt;

    &lt;!-- ApplicationContext설정 --&gt;
    &lt;context-param&gt;
        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
        &lt;param-value&gt;/WEB-INF/spring/root-context.xml&lt;/param-value&gt;
    &lt;/context-param&gt;

    &lt;!-- 리스너 등록 --&gt;
    &lt;listener&gt;
        &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
    &lt;/listener&gt;

    &lt;!-- 디스패처 서블릿 생성 및 매핑 --&gt;
    &lt;servlet&gt;
        &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
        &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/spring/appServlet/servlet-context.xml&lt;/param-value&gt;
        &lt;/init-param&gt;
        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
    &lt;/servlet&gt;

    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;

    &lt;!-- UTF-8필터 설정 --&gt;
    &lt;filter&gt;
        &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
        &lt;filter-class&gt;org.springframework.web.filter.CharacterEncodingFilter&lt;/filter-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;encoding&lt;/param-name&gt;
            &lt;param-value&gt;UTF-8&lt;/param-value&gt;
        &lt;/init-param&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;forceEncoding&lt;/param-name&gt;
            &lt;param-value&gt;true&lt;/param-value&gt;
        &lt;/init-param&gt;
    &lt;/filter&gt;

    &lt;filter-mapping&gt;
        &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
    &lt;/filter-mapping&gt;

&lt;/web-app&gt;
===============================================================
root-context.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd&quot;&gt;
&lt;/beans&gt;
===============================================================
servlet-context.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
    xmlns:mvc=&quot;http://www.springframework.org/schema/mvc&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd&quot;&gt;

    &lt;!-- 어노테이션 활성화 --&gt;
    &lt;mvc:annotation-driven&gt;&lt;/mvc:annotation-driven&gt;

    &lt;!-- view 경로 설정 --&gt;
    &lt;bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&gt;
        &lt;property name=&quot;prefix&quot; value=&quot;/WEB-INF/views/&quot; /&gt;
        &lt;property name=&quot;suffix&quot; value=&quot;.jsp&quot; /&gt;
    &lt;/bean&gt;

    &lt;!-- java공통패키지 스캔 --&gt;
    &lt;context:component-scan base-package=&quot;com.spring.test&quot;/&gt;
&lt;/beans&gt;
===============================================================
TestController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {

    @Autowired
    private TestService testservice;

    @RequestMapping(&quot;/hello&quot;)
    public String sysHello(Model model) {
        model.addAttribute(&quot;value&quot;, testservice.sayHello());
        return &quot;hello&quot;;
    }
}
===============================================================
TestService.java

import org.springframework.stereotype.Service;

@Service
public class TestService {

    public String sayHello() {
        return &quot;Spring_MVC&quot;;
    }
}
===============================================================

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] mybatis사용법]]></title>
            <link>https://velog.io/@marha-hwang/Spring-mybatis%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@marha-hwang/Spring-mybatis%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Wed, 07 Jun 2023 06:39:45 GMT</pubDate>
            <description><![CDATA[<h4 id="스프링에서-db를-연결하기-위해-다음과-같은-방법-사용">스프링에서 DB를 연결하기 위해 다음과 같은 방법 사용</h4>
<ol>
<li>SqlMapper/Mybatis</li>
</ol>
<ul>
<li>sql문과 자바코드를 설정 파일로 분리하여 코드의 수정이 일어나지 않게 함</li>
</ul>
<ol start="2">
<li>JPA/Hibernate </li>
</ol>
<ul>
<li>DB테이블을 객체로 구성하여 sql문 작성없이 DB쿼리 가능</li>
</ul>
<blockquote>
<p>이번 포스팅에서는 spring에서 mybatis를 사용하여 mysql과 연결하는 과정을 작성한다.</p>
</blockquote>
<blockquote>
<p>Spring에서 파일을 읽어오지 못하는 경우</p>
</blockquote>
<ul>
<li>Spring에서 Resources파일(ex: Java, xml, jsp등등)을 찾기 위해서는 해당 파일이 속하는 경로가 등록 되어 있어야 함</li>
<li>등록 방법 : Build Path -&gt; configure Build Path -&gt; 추가를 원하는 파일 경로 add</li>
<li>확인 : Java Resources에 추가한 파일 경로가 추가되어 있어야 함</li>
</ul>
<h3 id="1-pomxml에-모듈-추가">1. pom.xml에 모듈 추가</h3>
<ul>
<li><p>mybatis-spring : SqlSessionFactory, SqlSession 빈을 사용하기 위한 모듈</p>
<ul>
<li>mysql-connector-java : mysql Driver를 사용하기 위한 모듈<blockquote>
<p>해당 모듈 버전과 mysql버전을 일치 시켜야 함</p>
</blockquote>
</li>
<li>spring-jdbc : DriverManagerDataSource를 사용하기 위한 모듈<pre><code></code></pre></li>
</ul>
<!-- DB연결 -->
 <dependency> 
     <groupId>org.mybatis</groupId> 
     <artifactId>mybatis-spring</artifactId> 
     <version>1.2.4</version> 
 </dependency> 

 <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-jdbc</artifactId> 
     <version>5.3.22</version> 
 </dependency> 

 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>8.0.30</version>
 </dependency>
```
### 2. root-context.xml설정
-  dataSource, SqlSessionFactory, SqlSession 빈 등록
- component-scan을 통해 dao에 SqlSession주입
>  driverClassName : "com.mysql.jdbc.Driver"는 이전 버전에서 사용하던 드라이버명 최신 버전은 "com.mysql.cj.jdbc.Driver"와 같이 사용함
url :  “& amp;useSSL=false”를 사용하여야 SSL인증 오류를 막을 수 있음
```
 <context:component-scan base-package="com.spring.test"/>

 <!-- mysql접속 정보객체 -->
 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
     <property name="url" value="jdbc:mysql://localhost:3306/test_db?serverTimezone=Asia/Seoul&amp;useSSL=false"></property> 
     <property name="username" value="root"/>
     <property name="password" value="1111"/>
 </bean>

 <!-- mysql세션생성 객체 -->
 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
     <property name="dataSource" ref="dataSource"/>
     <property name="configLocation" value="WEB-INF/resources/mybatis-config.xml" /> <!-- mybatis 설정파일 등록 -->
 </bean>

 <!-- mysql세션 객체 -->
 <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
     <constructor-arg ref="sqlSessionFactory" />
 </bean>
```

</li>
</ul>
<h3 id="3-mybatis-configxml-설정">3. mybatis-config.xml 설정</h3>
<ul>
<li><p>typeAlias태그를 통해 사용할 DTO에 alias이름을 붙임</p>
</li>
<li><p>mapper태그를 통해 sql문이 작성된 xml파일을 등록함</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;!DOCTYPE configuration
PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot;
&quot;http://mybatis.org/dtd/mybatis-3-config.dtd&quot;&gt;
&lt;configuration&gt;
&lt;typeAliases&gt;
    &lt;typeAlias type=&quot;com.spring.test.TestDTO&quot; alias=&quot;user&quot;/&gt; &lt;!-- DTO객체에 alias이름 설정 --&gt;
&lt;/typeAliases&gt;

&lt;mappers&gt;
    &lt;mapper resource=&quot;WEB-INF/resources/mapper/testmapper.xml&quot; /&gt; &lt;!-- User관련 쿼리 파일 등록--&gt;
&lt;/mappers&gt;
&lt;/configuration&gt;</code></pre><h3 id="4-mapperxml설정---sql문-작성-파일">4. mapper.xml설정 - sql문 작성 파일</h3>
<ul>
<li>Namespace를 이용하여 해당 mapper파일에 이름을 붙임</li>
<li>select태그안에 sql문을 작성하고 해당 sql문을 지칭 할 id와 결과를 받을 Type을 설정<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;!DOCTYPE mapper
PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;
&lt;mapper namespace=&quot;UserMapper&quot;&gt; &lt;!-- Repository와 연동을 위해 사용될 namespace --&gt;
</code></pre></li>
</ul>
<select id="SelectUser" resultType="user"> 
    SELECT *
    FROM user
</select>
</mapper>
```
### 5. dao에서 SqlSession객체를 사용한 db접근
> mapper.xml에 지정된 namespace와 sql문의 id를 통해 쿼리를 수행한다 

</li>
</ul>
<pre><code>import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class TestDAO {

    @Autowired
    SqlSession session;

    public List&lt;TestDTO&gt; selectUser(){
        return session.selectList(&quot;UserMapper.SelectUser&quot;);
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 어노테이션]]></title>
            <link>https://velog.io/@marha-hwang/JAVA-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@marha-hwang/JAVA-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Tue, 30 May 2023 10:14:55 GMT</pubDate>
            <description><![CDATA[<h3 id="어노테이션이란">어노테이션이란?</h3>
<ul>
<li>프로그램에게 코드에 대한 정보를 전달하기 위한 메타데이터</li>
<li>사람에게는 주석을 이용하여 정보를 전달한다면, 프로그램에게는 어노테이션을 이용하여 정보를 전달한다</li>
<li>컴파일 또는 런타임시 코드를 어떻게 컴파일하고 처리 할 것인지 알려주는 정보</li>
</ul>
<h3 id="어노테이션의-사용이유">어노테이션의 사용이유?</h3>
<blockquote>
<p><strong>어노테이션이 아래 기능을 수행하는 것이 아닌 어노테이션과 리플렉션을 이용하여 수행</strong></p>
</blockquote>
<ul>
<li>컴파일시에 코드문법 체크 ex) @override</li>
<li>빌드시 코드를 자동으로 생성 ex) lombok라이브러리의 @getter, @setter</li>
<li>런타임시에 특정기능 수행 ex) Spring 프레임워크의 @Component, @Controller등등</li>
</ul>
<h3 id="리플렉션이란">리플렉션이란?</h3>
<blockquote>
<p>클래스의 구체적인 타입을 알지 못해도 그 클래스의 정보(타입, 메소드, 변수, 어노테이션 등)에 접근할 수 있도록 해주는 API</p>
</blockquote>
<ul>
<li>자바의 Class클래스를 이용하여 리플렉션 기능을 이용가능</li>
<li>예를들어 Spring에서 @Component가 붙은 클래스를 Bean으로 등록 하는 경우 어느 클래스에 @Component 어노테이션이 붙어 있는지 알지 못한다. 따라서 모든 클래스를 리플렉션을 이용하여 Scan후에 해당 어노테이션이 붙은 클래스만 bean으로 등록 가능하다</li>
</ul>
<h3 id="spring의-component-구현">Spring의 @Component 구현</h3>
<ul>
<li>@Component가 붙은 클래스를 bean으로 등록 해야한다. 하지만 어느 클래스에 @Component가 붙어 있는지는 바로 알 수 없다. 따라서 리플렉션(Class객체)을 이용하여 모든 클래스를 scan(for문과 if문)하면서 @Component가  붙은 클래스에 한해 bean객체를 생성하고 컨테이너에 저장한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Hash자료구조]]></title>
            <link>https://velog.io/@marha-hwang/JAVA-Hash%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@marha-hwang/JAVA-Hash%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Tue, 30 May 2023 06:36:44 GMT</pubDate>
            <description><![CDATA[<h3 id="hash자료구조-정리">hash자료구조 정리</h3>
<ul>
<li>Hash자료구조를 생성하면 내부적으로 배열이 생긴다</li>
<li>객체의 hashcode( )함수를 이용하여 객체의 해쉬값을 구한다.</li>
<li>객체의 해쉬값을 이용하여 인덱스를 구하고 배열에 객체를 저장한다
ex)해쉬값이 1235이면 1235%16 = 해당 인덱스</li>
<li>hashMap은 key의 해쉬값을 구해 알맞은 인덱스에 value를 저장하고, 검색시에는 key의 해쉬값을 구해 value가 저장된 인덱스를 바로 구한다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[완전탐색]오목 (백준2615)]]></title>
            <link>https://velog.io/@marha-hwang/%EC%99%84%EC%A0%84%ED%83%90%EC%83%89%EC%98%A4%EB%AA%A9-%EB%B0%B1%EC%A4%802615</link>
            <guid>https://velog.io/@marha-hwang/%EC%99%84%EC%A0%84%ED%83%90%EC%83%89%EC%98%A4%EB%AA%A9-%EB%B0%B1%EC%A4%802615</guid>
            <pubDate>Tue, 30 May 2023 06:27:45 GMT</pubDate>
            <description><![CDATA[<h3 id="문제요약">문제요약</h3>
<ul>
<li>흑돌과 백돌중 누가 이겼는지 판별하고 이긴 돌의 맨 왼쪽과 위의 좌표를 출력하는 문제</li>
</ul>
<h3 id="풀이-방법">풀이 방법</h3>
<ul>
<li>모든 위치를 순차적으로 탐색해 나가면서 승부가 결정 났는지 완전탐색으로 판별해나감</li>
</ul>
<h3 id="어려웠던-점">어려웠던 점</h3>
<ul>
<li>처음에는 완전탐색으로 풀릴 만한 간단한 문제인줄 알고 풀었지만 생각보다 처리해야 하는 경우의 수가 많아서 반례를 찾기 어려웠다</li>
<li>비효율적인 flag 사용으로 코드의 복잡도를 증가 시켰다<blockquote>
<p>flag의잘못된 사용
어느 상태를 만족시킬때 flag값을 변화시킴으로써 기록할때 사용해야 하는데 &quot;오목&quot;문제에서 나는 &#39;flag값이 변화하지 않았으면 어떤 상태를 만족시킨다&#39;라는 방식으로 사용하였다. 이때문에 flag값을 변화시키는 5목을 만족하지 않는 모든 경우에 대한 처리를 해주어야 했고 여기서 논리적인 빈틈이 생겨 문제를 풀기 어려웠었다</p>
</blockquote>
</li>
</ul>
<h3 id="풀이코드">풀이코드</h3>
<pre><code>/*
 * 문제 : 오목을 누가 이겼는지 판별하기 -&gt; 상,하,좌,우,대각선에서 5개가 연속으로 나타나는 경우 찾기
 * 생각해볼 것 : 
 * 반례 : 6목 확인을 위해 이전돌을 확인하는 과정에서 잘못된 if문과 flag값 세팅으로 반례발생
 * 
 * 문제풀이 : 완전탐색
 * 무엇을 탐색해야 하나? 모든 돌을 차례대로 탐색해나가야 한다.
 * 어떻게 탐색하나? 이긴돌의 가장 왼쪽 위의 돌을 출력 해야 하므로 가장 왼쪽부터 아래방향으로 탐색을 진행한다.
 * 탐색 해야 할 경우는? 모든 돌에 대하여 탐색
 * 각 돌을 탐색하는 방법은? 현재돌의 오른쪽, 아래, 대각선 탐색
 *  현재돌을 포함해 5번째 까지는 같은 돌이어야함, 6번째는 같지 않아야함
 *  또한 현재돌의 이전돌이 현재돌과 같지 않아야함
 * 
 */

 import java.util.*;
 import java.io.*;
public class Main {
    static int[][] arr;
    static int[][] Case = {{0,1}, {1,0}, {1,1}, {1,-1}};
    public static void main(String[] args) throws Exception{
        //입력받기
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        arr = new int[19][19];
        for(int i = 0; i&lt;19; i++){
            st = new StringTokenizer(in.readLine());
            for(int j=0; j&lt;19; j++){
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        //반복문 : 모든 돌에 대한 탐색
        boolean result = false;
        Loop1:
        for(int i=0; i&lt;19; i++){
            for(int j=0; j&lt;19; j++){
                //만약 현재 놓여진 돌이 없거나 승부가 났다면 break
                if(arr[j][i] == 0) continue;

                //결과 출력
                result = check(i, j);
                if(result){
                    System.out.println(arr[j][i]);
                    System.out.println(++j + &quot; &quot; + ++i);
                    break Loop1;
                }
            }
         }
         if(!result) System.out.print(0);

    }
     // 현재돌이 조건을 만족하는지 확인
    public static boolean check(int x, int y){
        boolean flag = false;

        //반복문 : 3가지 경우에 대한 탐색 - 가로, 세로, 대각선
        Loop1:
        for(int i = 0; i&lt;4; i++){
            int a = x-Case[i][0];
            int b = y-Case[i][1];
            //육목 확인을 위해 이전돌 확인
            if(a&gt;=0 &amp;&amp; b&gt;=0 &amp;&amp; a&lt;19 &amp;&amp; b&lt;19 &amp;&amp; arr[b][a] == arr[y][x]) {
                continue; 
            }
            //반복문 : 6번째 돌까지 확인
            int count = 5;
            for(int j=1; j&lt;6; j++){
                //확인 할 돌의 인덱스 구하기
                int nowX = x + j*Case[i][0];
                int nowY = y + j*Case[i][1];

                //인덱스를 초과하는 경우
                if(nowX&gt;=19 || nowY&gt;=19 || nowX&lt;0 || nowY&lt;0) {
                    if(j==5) break;
                    count-=1;
                    break;
                }
                //if : 5번째 미만의 돌이고, 다른 돌이면
                if(j &lt; 5 &amp;&amp; arr[y][x] != arr[nowY][nowX]) count-=1;
                //else if : 5번째 이상의 돌이고, 같은 돌이면
                else if(j==5 &amp;&amp; arr[y][x] == arr[nowY][nowX]) count-=1;
            }
            //조건을 만족하는 경우 종료
            if(count == 5){
                flag = true;
                break Loop1; 
            } 
        }
        return flag;

    }
}


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] IP주소체계]]></title>
            <link>https://velog.io/@marha-hwang/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-IP%EC%A3%BC%EC%86%8C%EC%B2%B4%EA%B3%84</link>
            <guid>https://velog.io/@marha-hwang/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-IP%EC%A3%BC%EC%86%8C%EC%B2%B4%EA%B3%84</guid>
            <pubDate>Mon, 22 May 2023 05:18:52 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이번 포스팅에서는 IPv4를 기준으로 IP주소체계를 정리한다
참고 - <a href="https://better-together.tistory.com/118">https://better-together.tistory.com/118</a></p>
</blockquote>
<h2 id="ip주소의-구성방식">IP주소의 구성방식</h2>
<ul>
<li>IP주소는 32비트로 나타내어지고 8비트씩 4부분으로 구분되어진다.</li>
<li>네트워크부와 호스트부로 구분되어진다.<blockquote>
<p>네트워크부와 호스트부 : 인터넷상에서 상대 host와 동일한 네트워크상에 위치하면 라우터 없이 호스트부를 이용해서 찾아갈 수 있지만 다른 네트워크상에 위치하면 라우터에서 네트워크부의 주소를 통하여 다른 네트워크로 라우팅 시켜야만 찾아갈 수 있다.</p>
</blockquote>
</li>
</ul>
<h2 id="ip주소의-클래스">IP주소의 클래스</h2>
<ul>
<li>IP주소에서 네트워크부를 구성하는 비트가 몇 비트인지에 따라 클래스가 구분된다</li>
<li>네트워크부를 구성하는 비트수가 적은 경우(ex A클래스) 그만큼 호스트부의 비트수도 많아지기 때문에 할당 가능한 호스트의 수도 많아진다.<blockquote>
<p>A클래스 : 처음 8비트 (첫 1비트는 클래스 식별비트)
B클래스 : 처음 16비트(첫 2비트는 클래스 식별비트)
C클래스 : 처음 24비트(첫 2비트는 클래스 식별비트)</p>
</blockquote>
</li>
</ul>
<h2 id="서브넷팅">서브넷팅</h2>
<ul>
<li>어느 네트워크가 클래스C방식을 사용하는 경우 256개의 IP를 생성 가능하지만, 
만약 56개의 host만 필요하다면 200개의 IP주소가 낭비되어지게 된다. 
따라서 이를 효율적으로 사용하기 위해 좀 더 작은 네트워크로 분할 하는 방식을 서브넷팅이라고 한다.</li>
</ul>
<h3 id="서브넷-분할-방법">서브넷 분할 방법</h3>
<blockquote>
<p>첫24비트가 네트워크부, 나머지 8비트가 호스트부인 C클래스의 경우</p>
</blockquote>
<ul>
<li>호스트부의 2비트를 서브넷부(네트워크부)로 할당하게 된다면 4개의 서로다른 네트워크를 가질 수 있는 서브넷이 생성가능하다.</li>
<li>이제 각 서브넷에서 호스트부의 길이는 6비트이기 때문에 각 서브넷마다 64(2^6)의 IP주소를 사용 가능하다.</li>
</ul>
<h2 id="서브넷-마스크">서브넷 마스크</h2>
<blockquote>
<p>서브넷을 사용하여 네트워크를 구성하는 경우 네트워크부와 호스트부를 구분하는 새로운 방식이 필요한데 이를 서브넷 마스크라고 한다</p>
</blockquote>
<p>서브넷 마스크는 32비트로 이루어져 있고, 각 비트는 IP 32비트에 대응한다</p>
<ul>
<li>IP주소의 네트워크부에 해당하는 서브넷 마스크 비트는 1로 설정</li>
<li>IP주소의 호스트부에 해당하는 서브넷 마스크 비트는 0으로 설정</li>
</ul>
<blockquote>
<p>서브넷 마스크 표기법</p>
</blockquote>
<ul>
<li>네트워크부의 비트가 24개인 경우</li>
</ul>
<p>11111111.11111111.11111111.00000000 = 255.255.255.0
십진수 표기법 - xxx.xxx.xxx.xxx /24
<br></p>
<ul>
<li>네트워크부의 비트가 26개인 경우</li>
</ul>
<p>11111111.11111111.11111111.11000000 = 255.255.255.192
십진수 표기법 - xxx.xxx.xxx.xxx /26</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[완전탐색] 꽃길(백준14620)]]></title>
            <link>https://velog.io/@marha-hwang/%EC%99%84%EC%A0%84%ED%83%90%EC%83%89-%EA%BD%83%EA%B8%B8%EB%B0%B1%EC%A4%8014620</link>
            <guid>https://velog.io/@marha-hwang/%EC%99%84%EC%A0%84%ED%83%90%EC%83%89-%EA%BD%83%EA%B8%B8%EB%B0%B1%EC%A4%8014620</guid>
            <pubDate>Fri, 19 May 2023 01:18:57 GMT</pubDate>
            <description><![CDATA[<h2 id="문제요약">문제요약</h2>
<ul>
<li>n*n크기의 마당에 3개의 꽃을 심는 최소비용 찾기, 단 마당을 벗어나거나 꽃이 겹치면 안됨</li>
</ul>
<h2 id="풀이-과정">풀이 과정</h2>
<p>완전탐색을 이용하여 풀이 </p>
<ul>
<li><p>무엇을 탐색해야 함? 꽃을 배치하는 모든 경우찾기</p>
</li>
<li><p>어떻게 모든 경우를 찾음? 가능한 자리에 하나씩 차례대로 배치</p>
</li>
<li><p>배치가 가능한 조건은? 마당 안에 있어야함, 겹치면 안됨</p>
</li>
<li><p>마당안에 있는지 확인하는 법은? 마당의 크기를 n+1*n+1로 표현하고 미리 체크해놓기</p>
</li>
<li><p>겹치는지 확인하는 법은? 마당을 배열로 표현하고 꽃이 위치할 지점이 체크 되었는지 확인 </p>
</li>
<li><p>DFS or BFS 무엇을 사용할지? 중복된 경우에서 우선순위가 존재하지 않기 때문에 그냥 BFS사용</p>
</li>
<li><p>depth기록을 위해 배열의 [0,0]인덱스에는 depth기록, 1번 인덱스부터 모양저장</p>
</li>
</ul>
<h2 id="개선할-점">개선할 점</h2>
<blockquote>
<ol>
<li>DFS를 사용할 경우 현재 상황을 기록하는 배열을 DFS함수의 인자로 넘기지 않고 구현하는 법</li>
</ol>
</blockquote>
<ul>
<li>DFS는 1가지의 경우를 완전히 탐색 후 다음 경우를 처음부터 완전히 탐색하는 성질을 이용한다</li>
<li><em>DFS함수가 끝난 후 바뀐 값을 원래대로 되돌리는 작업을 진행*</em>한다.<pre><code>arrCheck(i, j, true);
DFS(depth + 1, sum + tmpCost);
arrCheck(i, j, false);</code></pre></li>
</ul>
<blockquote>
<ol start="2">
<li>배열복사시 주의 해야 함!! 1차원 배열을 복사 하려면 값이 아닌 주소를 복사하기 때문에 clone()을 사용하여 복사함,<pre><code>             하지만 2차원 배열에서 clone사용시 배열의 값이 주소이기 때문에 clone를 사용하더라도 주소값을 복사하게 됨</code></pre></li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[sync/async 와 blocking/non-blocking개념]]></title>
            <link>https://velog.io/@marha-hwang/syncasync-%EC%99%80-blockingnon-blocking%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@marha-hwang/syncasync-%EC%99%80-blockingnon-blocking%EA%B0%9C%EB%85%90</guid>
            <pubDate>Wed, 10 May 2023 04:26:10 GMT</pubDate>
            <description><![CDATA[<p>** Sync/Async와 Blocking/Non-Blocking의 차이 : A함수가 B함수를 호출하는 경우를 가정**</p>
<h3 id="syncasync">Sync/Async</h3>
<p>B함수의 결과를 A함수에서 처리하는지에 대한 구분, Sync인 경우에는 B함수가 끝날 때까지 기다린 후 B의 결과를 A가 처리하지만, Async인 경우에는 B의 결과는 callback함수를 통해 처리한다</p>
<h3 id="blockingnon-blocking">Blocking/Non-Blocking</h3>
<p>실행의 제어권을 누가 가지느냐에 대한 구분, Blocking인 경우에는 A가 B를 호출한 경우에 B가 종료되기 전까지 B가 제어권을 가지지만, Non-Blocking인 경우에는 B가 실행된 직후 바로 리턴하여 제어권을 A에게 넘겨준다.</p>
<blockquote>
<p>소켓은 기본적으로 blocking모드이기 때문에 단일 스레드에서는 소켓통신을 하는 중에는 다른 작업을 진행하지 못한다. 하지만 소켓을 non-blocking모드로 전환하면 소켓함수가 실행되는 즉시 반환되어 다른 작업을 진행 할 수 있다. 이 때 지속적으로 통신이 완료되었는지를 확인 함으로써 완료처리를 한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[비트마스킹]]></title>
            <link>https://velog.io/@marha-hwang/%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9</link>
            <guid>https://velog.io/@marha-hwang/%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9</guid>
            <pubDate>Fri, 24 Feb 2023 07:23:13 GMT</pubDate>
            <description><![CDATA[<h2 id="비트-마스킹">비트 마스킹</h2>
<blockquote>
<p>각 요소들의 true/false여부를 저장 할 때 사용한다. 비트이기 때문에 오버헤드가 작다는 장점이 있다.</p>
</blockquote>
<ul>
<li>비트 연산(<a href="http://www.tcpschool.com/c/c_operator_bitwise">http://www.tcpschool.com/c/c_operator_bitwise</a>)</li>
</ul>
<h3 id="시프트-연산">시프트 연산</h3>
<p><img src="https://velog.velcdn.com/images/marha-hwang/post/3a546618-7ece-41a3-9c0d-640a0a282de4/image.png" alt=""></p>
<p>int num01 = 15; int num02 = 8;  </p>
<ul>
<li>~num01    // 1의 보수 – num01의 비트를 반전</li>
<li>num02 &lt;&lt; 1 // 곱하기 2 – num01의 비트를 왼쪽으로 1만큼 이동</li>
<li>num02 &gt;&gt; 1 // 나누기 2 – num01의 비트를 오른쪽으로 1만큼 이동</li>
</ul>
<h3 id="비트-마스킹-활용법">비트 마스킹 활용법</h3>
<blockquote>
<p>배열의 인덱스와 같이 0번부터 시작한다. 단 오른쪽부터 인덱스를 매긴다.</p>
</blockquote>
<ul>
<li>삽입 (false -&gt; true)
1010 에서 2번째 비트를 1로 바꾸기</li>
</ul>
<ol>
<li>1 &lt;&lt; 2 시프트 연산을 통해, 두번째 비트만 1인 0100 구하기</li>
<li>1010 | 0100 OR연산을 통해, 2번째 비트를 1로 바꾸기<br>결과 : 1110</li>
</ol>
<ul>
<li>삭제 (true -&gt; false)
1110 에서 2번째 비트를 0으로 바꾸기</li>
</ul>
<ol>
<li>~(1 &lt;&lt; 2) 시프트 연산을 통해, 두번째 비트만 0인 1011 구하기</li>
<li>1110 &amp; 1011 AND 연산을 통해 두번째 비트만 0으로 바꾸기
결과 : 1010</li>
</ol>
<ul>
<li>조회
1010 에서 3번째 비트가 true인지 확인</li>
</ul>
<ol>
<li>1 &lt;&lt; 3 시프트 연산을 통해, 3번째 비트만 1인 1000구하기</li>
<li>1010 &amp; 1000 AND연산을 통해 결과값이 1이상이면 true, 0이면 false</li>
</ol>
<p>int a = 5; // 0101
a |= (1&lt;&lt;3); //비트 켜기 1101
a &amp;= ~(1&lt;&lt;2); //비트 끄기 1001</p>
<p>System.out.print(a); //1001 = 9
//비트확인
System.out.print(a &amp; 1&lt;&lt;3); //3번째 비트 확인 1001이므로 true상태</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[짜잘짜잘 지식들]]></title>
            <link>https://velog.io/@marha-hwang/%EC%A7%9C%EC%9E%98%EC%A7%9C%EC%9E%98-%EC%A7%80%EC%8B%9D%EB%93%A4</link>
            <guid>https://velog.io/@marha-hwang/%EC%A7%9C%EC%9E%98%EC%A7%9C%EC%9E%98-%EC%A7%80%EC%8B%9D%EB%93%A4</guid>
            <pubDate>Fri, 20 Jan 2023 01:08:47 GMT</pubDate>
            <description><![CDATA[<h3 id="api와-라이브러리">API와 라이브러리</h3>
<p>라이브러리 - 자주 사용하는 기능이 구현된 코드
API - 한 프로그램에서 이미 구현된 다른 프로그램의 기능(자원)을 사용하기 위한 규약</p>
<blockquote>
<p>라이브러리와 API모두 이미 구현된 기능과 관련있다는 점이 비슷하여 헷갈리지만 라이브러리는 기능을 구현한 코드를 의미하고 API는 구현된 기능을 사용하기 위한 규약(인터페이스)이다. 따라서 라이브러리안에 API가 포함될 수도 있다</p>
</blockquote>
<p>HTTP API - HTTP프로토콜을 사용하여 다른 프로그램과의 인터페이스 수행
REST API - HTTP프로토콜과 비슷하나 HTTP API를 효율적으로 사용하기 위한 몇가지 제약조건이 추가 됨</p>
<blockquote>
<p>자원(데이터)에 접근하기 위한 인터페이스, 자원에 대한 CRUD기능을 수행</p>
</blockquote>
<blockquote>
<p>페이지 이동 시 브라우저에서 URL을 통해 요청을 하면 웹서버에서는 JS,HTML자원을 응답하여 주는데 이 과정이 API가 아닌 이유는?
웹에서의 API요청은 브라우저에서 웹서버로의 요청이 아닌 웹서버(html,js파일 포함)에서 백엔드 프로그램(ex 데이터베이스)으로의 요청을 의미하기 때문이다.</p>
</blockquote>
<h3 id="sql-group-by">SQL group by</h3>
<ul>
<li>group by 사용시 select에 집계함수와 group by의 대상이 된 컬럼만 사용 가능한 것이 아님</li>
<li>select절에 다른 컬럼 사용시 각 group의 첫번째 레코드의 값이 나옴</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>