1.  RelativeLayout

👩🏻‍🚀  렐러티브레이아웃은 상대 레이아웃이라고도 하며, 이름처럼 레이아웃 내부에 포함된 위젯을 상대적인 위치로 배치
👩🏻‍🚀  렐러티브레이아웃 안에 포함된 위젯은 렐러티브레이아웃의 어디쯤에 위치시킬 것인지 지정해야 함
👩🏻‍🚀  렐러티브레이아웃에 있는 위젯의 위치와 관련된 속성은 크게 두 부류로 나눌 수 있음
      1) 렐러티브레이아웃의 상하좌우에 배치하는 경우  2) 다른 위젯의 상대 위치에 배치하는 경우

 

상하좌우에 배치

  • layout_alignParentLeft
  • layout_alignParentRight
  • layout_alignParentTop
  • layout_alignParentBottom
  • layout_centerHorizontal
  • layout_centerVertical
  • layout_centerInParent

  ⚡️ 렐러티브레이아웃에 있는 위젯을 부모(렐러티브레이아웃)의 어느 부분에 위치시킬지를 결정. 각 속성의 값은 true 또는 false.
  ⚡️  예를 들어 우측하단에 위젯을 배치하려면 layout_alignParentBottom 과 layout_alignParentRight 속성에 true를 설정하면 됨

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="위쪽" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:text="좌측" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="중앙" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:text="우측" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="아래" />

</RelativeLayout>

 

 


 

다른 위젯의 상대 위치에 배치 

 

👾  렐러티브레이아웃 안에서 다른 위젯의 특정한 곳에 배치하는 방법. 다른 위젯과 관련된 속성.

👾  각 속성의 값에는 다른 위젯의 아이디를 지정하면 되는데 '@+id/기준 위젯의 아이디'와 같은 형식으로 사용

 

 

  • 상하좌우에는 layout_above, layout_below, layout_toLeftOf, layout_toRightOf
  • 상단, 중앙, 하단  layout_alignTop, layout_alignBaseline, layout_alignBottom
  • 좌측, 우측 기준에는 layout_alignLeft, layout_alignRight

 

        <Button
            android:id="@+id/baseButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="기준 위젯"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/baseButton"
            android:text="above"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/baseButton"
            android:text="below"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@+id/baseButton"
            android:text="toLeftOf"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@+id/baseButton"
            android:text="toRightOf"/>


 <Button
        android:id="@+id/baseButton"
        android:layout_width="wrap_content"
        android:layout_height="400dp"
        android:layout_centerInParent="true"
        android:text="기준 위젯"/>
    <Button
        android:layout_width="100dp"
        android:layout_height="70dp"
        android:layout_alignTop="@+id/baseButton"
        android:text="alignTop"/>
    <Button
        android:layout_width="100dp"
        android:layout_height="70dp"
        android:layout_alignBaseline="@+id/baseButton"
        android:text="alignBaseline"/>
    <Button
        android:layout_width="100dp"
        android:layout_height="70dp"
        android:layout_alignBottom="@+id/baseButton"
        android:text="alignBottom"/>

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  텍스트뷰

텍스트뷰는 View 클래스 바로 다음에 위치하며 다양한 위젯이 그 하위에 존재
텍스트뷰의 하위(에디트텍스트, 버튼, 체크박스 등)는 모두 텍스트뷰로부터 상속받는다.

속성 설명
text 텍스트뷰에 나타나는 문자열을 표현
'문자열'형식으로 값을 직접 입력하거나 '@string/변수이름'형식으로 설정한 후 
strings.xml 파일에 지정할 수 있음
textColor 글자의 색상을 지정
textSize 글자의 크기를 dp, px, in, mm, sp 단위로 지정
typeface 글자의 글꼴을 지정
값으로 sans, serif, monospace를 설정할 수 있고 디폴트는 normal
textStyle 글자의 스타일을 지정
값으로 bold, italic, bold|italic을 설정할 수 있고 디폴트는 normal
singleLine 글이 길어 줄이 넘어갈 경우 강제로 한 줄만 출력하고 문자열의 맨 뒤에 '...'를 표시
값으로 true와 false를 설정할 수 있고 디폴트는 false

 

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="textSize 속성"
        android:textSize="30dp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="textColor 속성"
        android:textColor="#00FF00"
        android:textSize="30dp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="textStyle 속성"
        android:textSize="30dp"
        android:textStyle="bold|italic" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="typeface 속성"
        android:textSize="30dp"
        android:typeface="serif" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:text="singleLine 속성 singleLine 속성 singleLine 속성"
        android:textSize="30dp" />


Kotlin 코드로 XML 속성 설정 

 

activity_main.xml파일에서 지정한 XML 속성을 Kotlin 코드에서도 설정 가능.

기본적인 텍스트뷰만 만들어 놓고 id속성과 text만 설정한 XML파일.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val textView1 = findViewById<TextView>(R.id.textView1)
        val textView2 = findViewById<TextView>(R.id.textView2)
        val textView3 = findViewById<TextView>(R.id.textView3)

        textView1.text = "안녕하세요?"
        textView1.setTextColor(Color.RED)
        textView2.textSize = 30.0f
        textView2.setTypeface(Typeface.SERIF, Typeface.BOLD_ITALIC)
        textView3.text = "가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하"
        textView3.isSingleLine = true
    }
}

 

  • textView1.setText("안녕하세요?")  : 첫 번째 텍스트뷰의 문자열을 변경
  • textView1.setTextColor(Color.RED) : 첫 번째 텍스트뷰의 색상을 빨간색으로 지정. 색상은 android.graphics.Color 클래스에 상수로 지정
  • textView2.setTextSize(30.0f) :  두 번째 텍스트뷰에 sp 단위의 폰트 크기를 지정 (XML 속성의 textSize="30sp"와 동일한 역할)
  • textView2.setTypeface(Typeface.SERIF, Typeface.BOLD_ITALIC) : 두 번째 텍스트뷰에 XML속성의 typeface와 textStyle 속성을 동시에 지정하는 메서드 (android.graphics.Typeface 클래스에 상수로 지정)
  • textView3.setText("가나다라마바사아자차카타파하가나다라마바사아자차카타파하")
  • textView3.setSingleLine() : 세 번째 텍스트뷰에 긴 글을 대입하고 XML 속성에서 singleLine="true" 효과를 줌

💫  XML 파일에서 설정하는 내용의 대부분이 메서드로 제공되어 Kotlin 코드에서 XML 설정이 가능

 


2.  버튼과 에디트텍스트

버튼과 에디트텍스트는 사용자에게서 어떤 값을 입력받기 위한 가장 기본적인 위젯으로 활용도가 높음.
두 위젯은 View 클래스와 TextView 클래스를 상속받으므로 거의 비슷하게 사용할 수 있음.

 

1) 버튼

버튼에서는 버튼을 클릭하는 이벤트

일반적인 버튼의 XML 코드


    A. 버튼 변수 선언    val myButton :Button
    B. 변수에 버튼 위젯 대입    myButton = findViewById<Button>(R.id.button1);
    C. 버튼을 클릭할 때 동작하는 클래스 정의

myButton.setOnClickListener {
// 동작 내용을 이 부분에 코딩
}


위의 세 단계는 대부분의 위젯(라디오버튼, 이미지버튼, 체크박스, 토글버튼 등)에서 거의 동일하게 사용

 

checkbox
 <CheckBox
        android:id="@+id/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="안드로이드폰" />

    <CheckBox
        android:id="@+id/iphone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="아이폰" />

    <CheckBox
        android:id="@+id/window"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="윈도우폰" />

 

radio button
    <RadioGroup
        android:id="@+id/rGroup1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <RadioButton
            android:id="@+id/radio0"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="true"
            android:text="남성" />

        <RadioButton
            android:id="@+id/radio1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="여성" />
    </RadioGroup>

 

switch & togglebutton
 <Switch
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="true" />

    <Switch
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="false" />

    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="true" />

    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="false" />



2) 에디트텍스트

에디트텍스트는 값을 입력받은 후 해당 값을 Java 코드에서 가져와 사용하는 용도로 많이 쓰임
에디트텍스트도 변수를 선언하고 이 변수에 해당 아이디 값을 넣은 후에 접근

XML 코드

 

    A. 에디트텍스트 변수 선언    var myEdit :EditText
    B. 변수에 에디트텍스트 위젯 대입    myEdit = findViewById<TextEdit>(R.id.edittext1);
    C. 에디트텍스트에 입력된 값 가져오기 ( 주로 버튼 클릭 이벤트 리스너 안에 삽입 )
         var myStr : String = myEdit.getText().toString();
          ✓ getText() 메서드는 에디트텍스트에 입력한 값을 반환. 이를 문자열로 바꾸기 위해 toString()을 사용
               반환값을 문자열로 변경할 때 가장 많이 사용하는 방식

 

 

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="아래에 이름을 입력 :"
        android:layout_margin="20dp"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="여기에 채우세요"
        android:layout_margin="20dp"/>

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="확인"
        android:layout_margin="20dp"/>

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  람다식   Lambda Expression

🚀  람다식은 람다 표현식, 람다라고도 불림
🚀  람다식을 한 줄로 표현하면 '람다식은 마치 값처럼 다룰 수 있는 익명함수'

      ⚡️  람다식을 값처럼 다룰 수 있다는 말은, 람다식 자체가 함수의 인수가 되거나 반환값이 될 수 있다는 의미

    val sayHello = fun() { println("Hello world!") }
    sayHello()

 

1)  람다식 정의

    ✓  람다를 이용하여, 인수 숫자의 제곱값을 반환

    val squareNum: (Int) -> Int = { number -> number * number }
    println(squareNum(12))
  • squareNum : 람다식을 저장할 변수의 이름을 지정
  • (Int) : 람다식의 인수 자료형을 지정
  • Int : 람다식의 반환 자료형을 지정. 이 경우에는 정수를 넣고 정수를 반환.
  • number : 인수 목록을 나열. number의 자료형은 자료형에서 명시해주었으므로 형추론이 되어 number는 Int가 됨.
  • number * number : 람다식에서 실행할 코드를 지정

 

 📌  자료형은 인수목록에서 명시해주어도 됨. 앞의 코드와 동일하게 작동하는 함수

    val squareNum2 = { number: Int -> number * number }
    println(squareNum2(12))

 

📌  람다식의 인수가 한 개이면 인수를 생략하고 it으로 지칭할 수 있음

    val squareNum3: (Int) -> Int = { it * it }
    println(squareNum3(12))

 


    2)  람다를 표현하는 다양한 방법

 람다는 '값처럼' 사용할 수 있는 익명 함수. 값처럼 사용한다는 것은 함수의 인수로도 넣어줄 수 있다.

    fun invokeLambda(lambda: (Int) -> Boolean): Boolean { //람다식을 인수로 받음.
        return lambda(5)
    }
    // 이 함수는 다음과 같이 람다식을 인수로 넣어 사용할 수 있음.
    val paramLambda: (Int) -> Boolean = { num -> num == 10 }
    println(invokeLambda(paramLambda)) // 람다식의 인수로 넣은 5 != 10 이므로 -> false
    // 변수를 사용하지 않고도 바로 넣어줄 수도 있음.
    // 다음의 람다식들은 모두 똑같이 작동
    invokeLambda({ num -> num == 10 }) // 람다식 바로 넣어주기
    invokeLambda({it == 10}) // 인수가 하나일 때 it으로 변경 가능
    invokeLambda(){ it == 10 } // 만약 함수의 마지막 인수가 람다일 경우 밖으로 뺄 수 있음.
    invokeLambda{ it == 10 } // 그 외 인수가 없을 때 () 생략 가능.

 

3)  SAM(Single Abstract Method) 변환

📍  안드로이드를 개발하다 보면 다음과 같은 코드를 아주 많이 작성하게 됨

    button.setOnClickListener {
        // 버튼이 눌렸을 때 작성할 코드
    }

 

  👾  함수의 인수가 하나이고 람다식인 경우에 ()를 생략하고 {}에 코드를 작성할 수 있음
  👾  setOnClickListener() 함수는 람다식이 아닌 OnClickListener 인터페이스를 인수로 받음

    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }


  👾  OnClickListener는 다음과 같이 추상 메서드 하나가 있는 인터페이스

public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }


  ⚡️  setOnClickListener 는 이와 같이 람다식이 아님에도 마치 람다식처럼 취급되고 있음
         ▶️  이것이 가능한 이유가 바로 자바 8에서 소개된 SAM 변환
             

🤓  SAM 변환은 두 가지 조건이 있다

    1. 코틀린 인터페이스가 아닌 자바 인터페이스
    2. 인터페이스 내에는 딱 한 개의 추상 메서드만 존재

    이 조건을 만족하는 경우 익명 인터페이스 객체 생성에 람다식을 사용할 수 있음.
    람다식을 사용하면 코드가 훨씬 간결해지고 가독성이 높아짐.

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  지연 초기화

코틀린은 지연 초기화를 사용하는데 이는 클래스의 코드에 Nullable 처리가 남용되는 것을 방지해 줌

 

1) lateinit

개발을 하다 보면 클래스 안에서 변수(프로퍼티)만 Nullable로 미리 선언하고 초기화(생성자 호출)를 나중에 해야 할 경우가 있는데, 이럴 경우 lateinit 키워드를 사용할 수 있음

Nullable로 선언하는 일반적인 방법


  👾  일반적인 선언 방식으로 처음에 null 값을 입력해두고, 클래스의 다른 메서드 영역에서 값을 입력함

class Person {
    var name: String? = null
    init {
        name = "Jane"
    }
    fun process() {
        name?.plus(" Messi")
        println("이름의 길이 = ${name?.length}")
        println("이름의 첫글자 = ${name?.substring(0, 1)}")
    }
}

 

  📍 이 방식은 변수에 입력된 값의 메서드나 프로퍼티를 사용할 때 Safe Call(?.)이 남용되어 가독성을 떨어트리는 문제가 있음

 

 lateinit을 사용하는 방법


  👾  lateinit을 사용하면 Safe Call을 쓰지 않을 수 있기 때문에 코드에서 발생할 수 있는 수많은 ?를 방지할 수 있음

class Person2 {
    lateinit var name: String
    init {
        name = "Jane"
    }
    fun process() {
        name.plus(" Messi")
        println("이름의 길이 = ${name.length}")
        println("이름의 첫글자 = ${name.substring(0, 1)}")
    }
}

 

 

lateinit의 특징


  ✓  var로 선언된 클래스의 프로퍼티에서만 사용할 수 있음
  ✓  null 은 허용되지 않음
  ✓  기본 자료형 Int, Long, Double, Float 등은 사용할 수 없음

  ✓  lateinit은 변수를 미리 선언만 해놓은 방식이기 때문에 초기화되지 않은 상태에서 메서드나 프로퍼티를 참조하면 null 예외가 발생해서 앱이 종료. 따라서 변수가 초기화되지 않은 상황이 발생할 수 있다면 Nullable이나 빈 값으로 초기화하는 것이 좋음

 


2)  lazy

👩🏻‍💻  lazy는 읽기 전용 변수인 val을 사용하는 지연 초기화
👩🏻‍💻  lateinit이 입력된 값을 변경할 수 있는 반면, lazy는 입력된 값을 변경할 수 없음
👩🏻‍💻  val로 변수를 먼저 선언한 후 코드의 뒤쪽에 by lazy 키워드를 사용, 그리고 by lazy 다음에 나오는 중괄호 {}에 초기화할 값을 써주면 됨

class Company {
    // by lazy를 사용하면 반환되는 값의 타입을 추론할 수 있기 때문에 변수의 타입을 생략할 수 있음.
    val person: Person by lazy { Person() }
    init {
        // lazy는 선언 시에 초기화 코드를 함께 작성 하기 때문에 초기화 과정이 필요없음.
    }
    fun process() {
        println("person은 이름은 ${person.name}") // 최초 호출하는 시점에 초기화.
    }
}

 

lazy의 특징


  ✓  선언 시에 초기화 코드를 함께 작성하기 때문에, 따로 초기화 할 필요가 없음
  ✓  lazy로 선언된 변수가 최초 호출되는 시점에 by lazy{} 안에 넣은 값으로 초기화
  ✓  코드에서 Company 클래스가 초기화 되더라도 person에 바로 Person()으로 초기화 되지 않고, process() 메서드에서 person.name이 호출되는 순간 초기화

💡  lazy는 주의해서 사용. 지연 초기화는 말 그대로 최초 호출되는 시점에 초기화 작업이 일어나기 때문에 초기화하는데 사용하는 리소스가 너무 크면 (메모리를 많이 쓰거나 코드가 복잡한 경우) 전체 처리 속도에 나쁜 영향을 미칠 수 있음

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  스프링 Web MVC의 특징

출처 :&nbsp;https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/spring-mvc-intro.html
출처 :&nbsp;https://tvd12.com/posts/spring-mvc-request-lifecycle

 

스프링 Web MVC는 기본적으로 서블릿 API를 좀 더 추상화된 형태로 작성된 라이브러리지만, 서블릿 / JSP를 사용할 때 필요한 많은 기능들을 기본적으로 제공해서 개발의 생산성과 안정성을 높여줌

 

  📍 스프링 Web MVC는 이름에서 알 수 있듯이 Web MVC 패턴으로 구현된 구조
  📍 스프링 Web MVC가 기존 구조에 약간의 변화를 주는 부분

Front-Contoller 패턴을 이용해 모든 흐름의 사전 / 사후 처리를 가능하도록 설계된 점
어노테이션을 적극적으로 활용해서 최소한의 코드로 많은 처리가 가능하도록 설계된 점
HttpServletRequest / HttpServletResponse를 이용하지 않아도 될 만큼 추상화된 방식으로 개발 가능

 

구성요소 설명
DispatcherServlet 클라이언트 요청을 전달받아 요청에 맞는 컨트롤러가 리턴한 결과값을 View에 전달하여 알맞은 응답을 생성
HandlerMapping 클라이언트의 요청 URL을 어떤 Controller가 처리할 지 결정
Controller 클라이언트의 요청을 처리한 뒤, 결과를 DispatcherServlet에게 리턴
ModelAndView Controller가 처리한 결과 정보 및 View 선택에 필요한 정보를 담음
ViewResolver Controller의 처리 결과를 생성할 View를 결정
View Controller의 처리 결과 화면을 생성

 

출처 : https://velog.io/@codemcd/


1)  DispatcherServlet 과 FrontController

스프링 MVC에서 가장 주요한 사실은 모든 요청 Request이 반드시 DispatcherServlet이라는 존재를 통해서 실행
  ✓ 
객체지향에서 이렇게 모든 흐름을 하나의 객체를 통해서 진행되는 패턴을 퍼사드 facade 패턴이라 하는데  구조에서는 Front-Controller 패턴 이라도 부름
  ✓ 
Front-Controller 패턴을 이용하면 모든 요청이 반드시 하나의 객체를 지나서 처리되기 때문에 모든 공통적인 처리를 프론트 컨트롤러에서 처리할 수 있게 됨

 

 

 

👾  스프링 MVC에서는 DispatcherServlet이라는 객체가 프론트 컨트롤러의 역할을 수행
👾  프론트 컨트롤러가 사전 / 사후에 대한 처리를 하게 되면 중간에 매번 다른 처리를 하는 부분만 별도로 처리하는 구조를 만들게 됨 

     ➡️  스프링 MVC 에서는 이를 컨트롤러라고 하는데 @Controller를 이용해서 처리

 

 

 


2)  스프링 MVC 사용하기

👻  spring-webmvc 라이브러리는 미리 추가되었으므로 스프링 MVC관련 설정을 추가 

 

㉮  스프링 MVC관련 설정을 추가하기 위해 WEB-INF 폴더에 servlet-context.xml 파일을 생성
  ✓  root-context.xml을 이용할 수도 있지만, 일반적으로는 구조를 분리하듯이 웹을 다루는 영역이라 별도의 설정 파일을 이용하는 것이 일반적이다.

 

㉯  프로젝트 내부의 webapp 폴더 아래에 'resources'라는 폴더를 하나 더 생성해 둠

  ✓  나중에 정적 파일들(html, css, js, 이미지등)을 서비스하기 위한 경로

 

 servlet-context.xml  설정 코드
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
        
    <mvc:annotation-driven/>
    <mvc:resources mapping="/resources/**" location="/resources/"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

 

  ⚡️  <mvc:annotation-driven> 설정 : 스프링 MVC 설정을 어노테이션 기반으로 처리한다는 의미와 스프링 MVC의 여러 객체들을 자동으로 스프링의 빈으로 등록하게 하는 기능을 의미
  ⚡️  <mvc:resources> 설정 : 이미지나 html 파일과 같이 정적인 파일의 경로를 지정
        ✓  /resources 경로로 들어오는 요청은 정적 파일을 요구하는 것이라고 생각하고 스프링 MVC에서 처리하지 않는다는 의미
        ✓  location 속성 값은 webapp 폴더에서 만들어둔 폴더를 의미
        ✓  InternalResourceViewResolver라는 이름의 클래스로 빈이 설정되어 있는데,
             InternalResourceViewResolver는 스프링 MVC에서 제공하는 뷰(view)를 어떻게 결정하는지에 대한 설정을 담당
        ✓  prefix와 suffix는 뷰를 이용할때 파일명만 주어지면 조합해서 '/WEB-INF/view/파일명.jsp' 같은 형식을 만들 수 있음

 

 

web.xml의 DispatcherServlet 설정

 

스프링 MVC를 실행하려면 front controller 역할을 하는 DispatcherServlet을 설정해야하는데,  web.xml을 이용해서 처리

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

 

  ⚡️  <servlet> 설정과 <servlet-mapping> 설정이 추가
        ✓  <servlet> 설정은 DispatcherServlet을 등록하는데 DispatcherServlet이 로딩할 때 servlet-context.xml을 이용하도록 설정
        ✓  load-on-startup 설정의 경우 톰캣 로딩 시에 클래스를 미리 로딩해 두기 위한 설정
        ✓  <servlet-mapping> 설정모든 경로의 요청에 대한 처리를 담당하기 때문에 '/'로 지정

 


3)  스프링 MVC 컨트롤러 

스프링 MVC 컨트롤러는 전통적인 자바의 클래스 구현 방식과 다름

스프링 MVC의 컨트롤러 특징

 

  ✓  상속이나 인터페이스를 구현하는 방식을 사용하지 않고 어노테이션만으로 처리가 가능
  ✓  오버라이드 없이 필요한 메소드들을 정의
  ✓  메소드의 파라미터를 기본 자료형이나 객체 자료형을 마음대로 지정
  ✓  메소드의 리턴타입도 void, String, 객체 등 다양한 타입을 사용할 수 있음

 

㉮  controller 패키지를 추가하고 SampleController 클래스를 추가

@Log4j2
@Controller
public class SampleController {

    @GetMapping("/hello")
    public void hello() {
        log.info("hello(_)...");
    }
}

 

  ⚡️  몇 가지 특이한 어노테이션들이 사용
      ✓  @Controller는 해당 클래스가 스프링 MVC에서 컨트롤러 역할을 한다는 것을 의미하고 스프링의 빈으로 처리되기 위해서 사용
      ✓  @GetMapping은 GET 방식으로 들어오는 요청을 위해 사용

 


 

A) servlet-context.xml의 component-scan


controller 패키지에 존재하는 컨트롤러 클래스들을 스프링으로 인식하기 위해서는 해당 패키지를 스캔해서 @Controller 어노테이션이 추가된 클래스들의 객체들을 스프링이 빈으로 설정되게 만들어야 함

servlet-context.xml에 component-scan을 적용
<context:component-scan base-package="com.example.spring.controller"/>

 

WEB-INF에 view 폴더 생성후 hello.jsp 작성
<html>
<head>
    <title>Title</title>
</head>
<body>
  <h1>Hello JSP</h1>
</body>
</html>


 

B) @RequestMapping과 파생 어노테이션들


스프링 컨트롤러에서 가장 많이 사용하는 어노테이션은 @RequestMapping
  ⚡️  @RequestMapping은 말 그대로 '특정한 경로의 요청 Request을 지정'하기 위해서 사용
  ⚡️  컨트롤러 클래스의 선언부에도 사용할 수 있고, 컨트롤러의 메서드에도 사용할 수 있음

 

controller 패키지에 TodoController 클래스 추가
@Log4j2
@Controller
@RequestMapping("/todo")
public class TodoController {
    @RequestMapping("/list")
    public void list() {
        log.info("todo list...");
    }

    @RequestMapping(value = "/register", method = RequestMethod.GET)
    public void register() {
        log.info("todo register...");
    }
}

 

  ⚡️  TodoController의 @RequestMapping의 value 값은 '/todo'이고 list()는 '/list'이므로 최종경로는 '/todo/list' 
  ⚡️  JSP 파일이 없어서 에러가 나지만 로그 출력은 확인

 

  ⚡️  @RequestMapping을 이용하는 것만으로도 여러 개의 컨트롤러를 하나의 클래스로 묶을 수 있고, 각 기능을 메소드 단위로 설계할 수 있게 되므로 실제 개발에서 많은 양의 코드를 줄일 수 있음

  ⚡️  @RequestMapping에는 method 속성을 이용해서 GET / POST 방식을 구분해서 처리했지만, 스프링 4버전 이후에는 @GetMapping, @PostMapping 어노테이션이 추가되면서 GET / POST 방식을 구분해서 처리할 수 있게 됨
      ➡️  예를 들어 Todo 등록의 경우 GET 방식으로 '/todo/register'를 이용하면 입력 가능한 화면을 보여주고, POST방식은 처리를 해야 함

@Log4j2
@Controller
@RequestMapping("/todo")
public class TodoController {
    @RequestMapping("/list")
    public void list() {
        log.info("todo list...");
    }

//    @RequestMapping(value = "/register", method = RequestMethod.GET)
    @GetMapping("/register")
    public void register() {
        log.info("todo register...");
    }

    @PostMapping("/register")
    public void registerPOST(TodoDTO todoDTO) {
        log.info("POST todo register...");
        log.info(todoDTO);
    }
}

 


C)  파라미터 자동 수집과 변환


👩🏻‍💻  스프링 MVC가 인기를 끌게 된 여러 이유 중에는 개발 시간을 단축할 수 있는 편리한 기능들이 많기 때문
👩🏻‍💻  개발자들에게 가장 필요한 파라미터 자동 수집 기능

 

  ⚡️  파라미터 자동 수집 기능은 간단히 말해서 DTO나 VO등을 메서드의 파라미터로 설정하면 자동으로 전달되는

         HttpServletRequest의 파라미터들을 수집해 주는 기능
  ⚡️  단순히 문자열만이 아니라 숫자도 가능하고, 배열이나 리스트, 첨부 파일도 가능

 

파라미터 수집은 다음과 같은 기준으로 동작


  ✓  기본 자료형의 경우는 자동으로 형 변환처리가 가능
  ✓  객체 자료형의 경우는 setXXX()의 동작을 통해서 처리
  ✓  객체 자료형의 경우 생성자가 없거나 파라미터가 없는 생성자가 필요

 

단순 파라미터의 자동 수집

 

  📍 SampleController에 ex1() 추가

    @GetMapping("/ex1")
    public void ex1(String name, int age) {
        log.info("ex1() ...");
        log.info("name: " + name);
        log.info("age: " + age);
    }

 

  ✓  문자열 name과 int 타입의 age 선언
  ✓  브라우저를 이용해서 name과 age를 지정하면 'ex1?name=aaa&age=16'와 같이 호출 되었을 때 자동으로 처리되는 것 확인

 

 

  

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  레이아웃 개념

레이아웃은 ViewGroup 클래스로부터 상속받으며 내부에 무엇을 담는 용도로 쓰임. 즉 레이아웃 안에 존재하는 위젯을 배치하게 해준다.
레이아웃 중에서 가장 많이 사용되는 것은 리니어레이아웃이며, 이를 선형 레이아웃이라고도 함

 

레이아웃의 대표적인 속성

 

속성 설명
orientation 레이아웃 안에 배치할 위젯의 수직 또는 수평 방향을 설정
gravity 레이아웃 안에 배치할 위젯의 정렬방향을 좌측, 우측, 중앙 등으로 설정
padding 레이아웃 안에 배치할 위젯의 여백을 설정
layout_weight 레이아웃이 전체 화면에서 차지하는 공간의 가중값을 설정
여러 개의 레이아웃이 중복될 때 주로 사용
baselineAligned 레이아웃 안에 배치할 위젯을 보기 좋게 정렬

 

 

2.  레이아웃의 종류

종류 설명
LinearLayout (선형 레이아웃) 레이아웃의 왼쪽 위부터 아래쪽 또는 오른쪽으로 차례로 배치
RelativeLayout(상대 레이아웃) 위젯 자신이 속한 레이아웃의 상하좌우 위치를 지정하여 배치하거나 
다른 위젯으로부터 상대적인 위치를 지정
TableLayout 행과 열의 개수를 지정한 테이블 형태로 위젯을 배열
GridLayout 테이블레이아웃과 비슷하지만 행 또는 열을 확장하여 다양하게 배치할 때 더 편리
FrameLayout 위젯을 왼쪽 위에 일률적으로 겹쳐서 배치하여 중복되어 보이는 효과를 낼 수 있음
여러 개의 위젯을 배치한 후 상황에 따라서 필요한 위젯을 보이는 방식을 주로 활용
리니어레이아웃만으로도 대부분의 레이아웃 형태를 구성할 수 있어 리니어레이아웃의 사용도가 가장 높음.

 


1) 리니어 레이아웃 

기본 리니어레이아웃의 형태


📍  orientation
     리니어레이아웃의 가장 기본적인 속성은 orientation이며, 값으로 vertical과 horizontal을 설정. vertical은 레이아웃 안에 포함될 위젯의 배치를 왼쪽 위부터 수직방향으로 쌓겠다는 의미이고, horizontal은 수평 방향으로 쌓겠다는 의미

 

📍 gravity와 layout_gravity 
     gravity 속성으로 레이아웃 안의 위젯을 어디에 배치할 것인지를 결정하며 값으로 left, right, center, top, bottom 등을 사용할
수 있음. 2개를 조합하여 right|bottom 처럼 사용할 수 있는데, 오른쪽 아래에 정렬한다는 의미

    gravity 속성이 자신에게 포함된 자식(주로 위젯)을 어디에 위치시킬지를 결정한다면, layout_gravity 속성은 자신의 위치를 부모(주로 레이아웃)의 어디에 위치시킬지 결정. 그래서 gravity는 레이아웃에, layout_gravity는 위젯에 주로 지정.

 

 📍 baselineAligned
      baselineAligned 속성은 크기가 다른 위젯들을 보기 좋게 정렬해주는 것으로 true와 false를 지정.
      baselineAligned 속성의 디폴트 값은 true이므로 생략해도 잘 배치되기 때문에 특별히 신경 쓰지 않아도 됨.

 


2)  중복 리니어레이아웃 형태

한 화면에 위젯을 수평과 수직으로 다양하게 배치해야 하는 경우, 리니어레이아웃 안에 리니어레이아웃을 생성하는 방식을 사용.

 

📍  layout_weight 

     리니어레이아웃을 여러 개 사용할 경우 각 레이아웃의 크기를 지정해야 함. 레이아웃을 화면 전체에 채워야 하기 때문에 dp, px 등의 단위로 지정하기 보다는 주로 전체 화면에 대한 비율(%)로 지정. 이 때 사용하는 것이 layout_weight 속성.

중첩 LinearLayout xml 파일로 구현
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:gravity="center"
        android:orientation="vertical"
        android:layout_weight="1">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="버튼1" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="버튼2" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:background="#C7ECC7"
        android:gravity="center"
        android:orientation="horizontal"
        android:layout_weight="2">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="버튼3" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="버튼4" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:background="#B5B5F6"
        android:gravity="center"
        android:orientation="vertical"
        android:layout_weight="1">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="버튼5" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="버튼6" />
    </LinearLayout>

</LinearLayout>

 

 

 

[ 내용 참고 : IT 학원 강의 ]

+ Recent posts