728x90

오늘부터 애기를 재우고 1시간씩 사이드 프로젝트를 해보겠습니다..


.\mvnw spring-boot:run
 

1. .\

현재 폴더(Current Directory)를 의미한다.

즉,

"현재 프로젝트 안에 있는 파일을 실행해."

라는 뜻이다.


2. mvnw

아까 네 프로젝트에 생긴 이 파일 기억나지?

mvnw
mvnw.cmd
 

이게 Maven Wrapper다.

원래는 컴퓨터에 Maven을 설치해야 하지만,

Spring Boot 프로젝트를 만들면 프로젝트 안에 Maven이 같이 들어온다.

그래서 아까

 
mvn -version
 

은 안 됐지만,

 
.\mvnw
 

는 된다.


3. spring-boot:run

Maven에게

"Spring Boot 프로젝트를 실행해."

라고 시키는 명령이다.


쉽게 말하면

 
.\mvnw spring-boot:run
 

=

"이 프로젝트를 실행해."

참고로 앞으로 자주 쓰는 명령어

 
.\mvnw clean
 

👉 이전 빌드 결과 삭제

 
.\mvnw test
 

👉 테스트 실행

 
.\mvnw package
 

👉 배포용 JAR 파일 생성

 
.\mvnw spring-boot:run
 

👉 개발 서버 실행

 


VS Code에서 Spring Boot 개발환경 구축 (Java + Spring Boot)

개발 환경

  • IDE : VS Code
  • JDK : Java 17 (17.0.12)
  • Build Tool : Maven
  • Framework : Spring Boot 3.x
  • OS : Windows 10

1. Java 설치 확인

터미널에서 아래 명령어를 실행한다.

 
java -version
 

결과

openjdk version "17.0.12"
 

Java 17 이상이면 Spring Boot 3를 사용할 수 있다.

추가로 컴파일러도 확인한다.

 
javac -version
 

2. VS Code 확장 프로그램 설치

VS Code에서

Ctrl + Shift + P
 

를 누른다.

검색창에

Extensions: Install Extensions
 

또는

Ctrl + Shift + X
 

를 눌러 Extensions 화면으로 이동한다.

다음 확장 프로그램을 설치한다.

필수

  • Extension Pack for Java (Microsoft)
  • Spring Boot Extension Pack (VMware)

선택

  • Maven for Java
  • Lombok Annotations Support for VS Code

3. Spring Boot 프로젝트 생성

다시

Ctrl + Shift + P
 

입력 후

Spring Initializr: Create a Maven Project
 

선택한다.

설정은 아래와 같이 진행했다.

항목설정
Build Tool Maven
Language Java
Spring Boot 최신 Stable
Group com.takerp
Artifact erp
Packaging Jar
Java 17

Dependencies는 다음만 선택했다.

  • Spring Web
  • MySQL Driver
  • Lombok
  • Spring Boot DevTools

Spring Data JPA는 선택하지 않았다.

이번 프로젝트는 SQL 중심의 ERP를 만들 예정이라 MyBatis를 사용할 계획이다.


4. 프로젝트 열기

생성이 완료되면 VS Code가 프로젝트를 자동으로 연다.

프로젝트 구조

erp
├── src
├── mvnw
├── mvnw.cmd
├── pom.xml
└── ...
 

5. Maven 실행

VS Code 터미널에서

 
.\mvnw spring-boot:run
 

실행한다.

명령어 설명

.\mvnw
 

현재 프로젝트에 포함된 Maven Wrapper 실행

spring-boot:run
 

Spring Boot 서버 실행

즉,

 
.\mvnw spring-boot:run
 

Spring Boot 서버를 실행하는 명령어이다.


6. 서버 실행 확인

브라우저에서

http://localhost:8080
 

접속한다.

처음에는 아래와 같은 화면이 나온다.

Whitelabel Error Page

This application has no explicit mapping for /error,
so you are seeing this as a fallback.
 

이 화면은 오류가 아니라 정상 동작이다.

이유는 아직 / 요청을 처리하는 Controller를 만들지 않았기 때문이다.


7. 패키지명 변경

프로젝트 생성 시 패키지가

com.takerp.erp_backend
 

으로 생성되었지만,

Java 패키지 네이밍 관례에 맞게

com.takerp.erp
 

로 변경하였다.

변경 후에는 반드시 서버를 다시 실행해야 한다.

 
.\mvnw spring-boot:run
 

Java 코드를 수정해도 서버가 자동 재시작되지 않는 경우가 있으므로 변경 후에는 서버 상태를 확인하는 습관을 들이자.


오늘 배운 내용

  • Java 17 설치 여부 확인
  • VS Code Java 개발환경 구축
  • Spring Initializr로 프로젝트 생성
  • Maven Wrapper(mvnw)의 역할
  • Spring Boot 서버 실행 방법
  • Whitelabel Error Page가 나타나는 이유
  • Java 패키지 네이밍 규칙
  • 코드 변경 후 서버 재시작의 중요성

@RestController

"이 클래스는 웹 요청을 받아서 데이터 그대로 응답하는 컨트롤러야!"

  • 역할: 클래스 상단에 붙여서, 해당 클래스가 외부에서 들어오는 HTTP 요청을 처리하는 웹 컨트롤러임을 스프링에게 알립니다.
  • 핵심 특징: @Controller와 @ResponseBody라는 두 어노테이션이 하나로 합쳐진 녀석입니다.
    • 기존 @Controller는 HTML 파일(뷰)을 찾아 반환하지만, @RestController는 메소드가 리턴하는 값("Hello ERP!")을 HTML 페이지가 아닌 순수 데이터(문자열, JSON 등) 자체로 웹 브라우저에 직접 전달합니다.

2. @GetMapping("/")

"누군가 루트 주소(/)로 GET 요청을 보내면 이 메소드를 실행해!"

  • 역할: 특정 HTTP 요청 경로(URL)와 방식을 아래 작성된 메소드(home())에 매핑(연결)해 줍니다.
  • 상세 동작:
    • GET 방식: 브라우저 주소창에 http://localhost:8080/을 입력하고 엔터를 치는 것과 같은 기본적인 페이지 조회/데이터 요청 방식입니다.
    • "/" (경로): 도메인의 가장 기본 경로(루트 주소)를 의미합니다.
    • 따라서 http://localhost:8080/으로 접속하면, 스프링이 이 어노테이션을 보고 home() 메소드를 실행시켜 화면에 "Hello ERP!"라는 문자를 띄워주게 됩니다.

 

근데 @Controller와 @ResponseBody를 언제 왜 합쳐서 @RestController 로 사용하게 되었을까?

제미나이한테 물어봤다.

스프링 프레임워크 개발진이 "자주 함께 쓰는 두 어노테이션을 매번 따로 적는 게 귀찮으니, 하나로 합친 메타 어노테이션(Meta-Annotation)을 만들자!" 해서 만든 게 바로 @RestController입니다.

스프링 부트 1.0(Spring Framework 4.0) 시절부터 도입된 기능인데요, 내부 구조를 보면 비밀이 바로 풀립니다.

@RestController 내부의 비밀

실제 스프링 내부의 @RestController 정의 코드를 까보면 이렇게 생겼습니다.

Java
 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller    // 1. 기존 Controller 포함
@ResponseBody  // 2. ResponseBody 포함
public @interface RestController {
    // ...
}

스프링 어노테이션은 다른 어노테이션 위에 또 어노테이션을 붙이는 겹치기(Meta-Annotation)가 가능합니다.

즉, @RestController를 클래스 위에 한 줄만 붙여도, 스프링은 자바의 메타데이터를 읽어 내부적으로 @Controller + @ResponseBody가 둘 다 붙어있는 것으로 똑같이 인식하는 원리입니다.

왜 이렇게 만들었을까요?

과거에는 서버가 HTML 웹페이지를 그려서 보내주는 MVC 패턴(JSP, Thymeleaf 등)이 주를 이뤘습니다.

  • 과거 (웹페이지 반환 위주): 대부분 HTML을 반환해야 하므로 기본은 @Controller로 쓰고, 아주 가끔 Ajax 요청 같은 데이터 반환이 필요할 때만 메서드 위에 @ResponseBody를 얹어 썼습니다.
  • 현재 (REST API / SPA / 앱 백엔드 위주): React, Vue, mobile 앱처럼 백엔드는 오직 JSON 데이터만 주고받는 형태가 표준이 되었습니다. 그러다 보니 컨트롤러 안에 있는 모든 메서드에 @ResponseBody를 도배해야 하는 상황이 생긴 거죠.
Java
 
// ❌ 옛날 방식: 클래스 내 모든 메서드에 @ResponseBody를 붙여야 했음
@Controller
public class HomeController {
    
    @GetMapping("/user")
    @ResponseBody
    public User getUser() { ... }

    @GetMapping("/item")
    @ResponseBody
    public Item getItem() { ... }
}

이런 번거로움을 해결하기 위해, 클래스 단위에 @RestController만 한 번 딱 붙이면 내부의 모든 @GetMapping 메서드에 @ResponseBody가 자동으로 적용되도록 발전한 것입니다.

728x90

728x90

그래들(Gradle)은 그루비(Groovy)를 기반으로 한 빌드도구이다.

근데 그루비는 뭐냐
JVM에서 실행되는 스크립트 언어로 자바를 기반으로 만들어서 자바랑 비슷하다
JVM에서 돌아가기 때문에 자바API도 사용 가능하다.

 

그래들(Gradle)은 그루비(Groovy)로 만들었고 요즘 메이븐(Maven) 대신 쓰는 빌드도구다.
그래들은 Ant와 Maven의 장점을 모아서 만들었다.

내가 궁금했던거는 lombok같은 라이브러리를 build.gradle 파일의 dependencies에 추가해야 하는데
dependency configuration(의존성 구성)이 뭐 이리 많은지..
dependency configuration는 라이브러리들이 적용될 범위를 정하는 곳이다.
아래는 공식문서다. 영어 잘하면 아래에서 보면된다.
https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management

 

The Java Plugin

If a dependent project has changed in an ABI-compatible way (only its private API has changed), then Java compilation tasks will be up-to-date. This means that if project A depends on project B and a class in B is changed in an ABI-compatible way (typicall

docs.gradle.org

dependency configuration의 종류는 아래와 같다

- implementation
- compile
- compileOnly
compileClasspath extends compileOnly, implementation
annotationProcessor
runtimeOnly
runtimeClasspath extends runtimeOnly, implementation
testImplementation extends implementation
testCompileOnly
testCompileClasspath extends testCompileOnly, testImplementation
testRuntimeOnly extends runtimeOnly
testRuntimeClasspath extends testRuntimeOnly, testImplementation
archives
default extends runtimeElements

compile은 연결된 API 모두가 프로젝트에 의해 노출되고
implementation은 노출되지 않는다.
runtimeOnly는 runtime 시에만 필요한 라이브러리 일때 사용

test들어간거는 테스트 수행시에만 적용되는거 등등

출처: https://kotlinworld.com/316

 

[Gradle] build.gradle의 dependencies 블록 한 번에 정리하기. implementation, testImplementaion의 차이와 라이브

dependencies 블록이란? dependencies 블록은 프로젝트를 구성하기 위해 받아와야 할 라이브러리를 정의해놓는 공간이다. dependencies 블록에는 보통 다음과 같은 문법이 들어간다. dependencies { implementation(

kotlinworld.com

 

728x90

'개념정리' 카테고리의 다른 글

CDN  (0) 2022.02.09
절대경로, 상대경로  (0) 2022.01.05
서블릿 (Servlet)  (0) 2021.10.25
JSP (Java Server Page)  (0) 2021.10.25
정규표현식  (0) 2021.08.09
728x90

자바스크립트에서 array, object 안에 있는 데이터를 빼서 변수로 만들고 싶을 때 사용

let 사람 = { student : true, age : 20 }
let student = 사람.student;
let age = 사람.age

이렇게 하던거를 더 편하게 할 수 있게 만들어놨다.

//오브젝트
let { student, age } = { student : true, age : 20 }
console.log(student); //true

//배열
let [a, b] = ['안녕', 100]
console.log(a); //안녕

위의 코드 처럼 사용하면 변수를 쉽게 뺄수 있다.
근데 오브젝트에서 더 정확하게 하기 위해서는

let { student : a , age : b } = { student : true, age : 20 };
console.log(b); //20

좌우를 맞춰줘야 한다.

 


Destructuring 문법도 함수 파라미터에 사용이 가능하다.

왜냐면 함수 파라미터 작명하는 것도 변수만드는 문법과 똑같아서 그렇다.

Destructuring 문법을 사용하기 전에는 아래 처럼 작성하면 변수를 빼서 사용할 수 있다.

let person = { student : true, age : 20 }

function 함수(a, b){
  console.log(a, b)
}
함수(person.student, person.age)

Destructuring 문법을 사용하면  ▼

let person = { student : true, age : 20 }

function 함수({student, age}){
  console.log(student, age)
}
함수({ student : true, age : 20 })

?? 안쉽다..... 나중에 알아보자

그니까 파라미터 변수만들 때 { student, age }라고 쓰면

파라미터로 들어오는 { student : 어쩌구 }는 student 라는 변수에 저장해주세요~

파라미터로 들어오는 { age : 어쩌구 }는 age 라는 변수에 저장해주세요~

라는 뜻입니다. (object 자료니까 변수 작명할 때 object 속성명으로 잘 작명해야함)

항상 같은 모습의 object, array 자료가 들어올 때 쓰는 문법이라고 보면 되겠습니다

728x90
728x90

rest parameter

함수 (...작명){ }

...작명을 하면 파라미터를 여러개 받을 수 있고

함수 (x,...작명){ }
함수 (x,y...작명){ }

x,...작명 은 필수적으로 한개의 파라미터가 필요한다는 의미이다.
x,y,...작명 는 필수적으로 3개의 파라미터가 필요하다는 의미.

...작명 (rest parameter)를 사용할려면 파라미터를 명시하는 곳에서 제일 마지막에 선언하면 된다.

그리고 rest 파라미터자리에 집어넣은 값들은 전부 [ ] 안에 담긴다.


Spread operator

자바스크립트에서 ...을 쓰는 또다른 기능중 하나는 배열이나 오브젝트를 벗길때 사용하는 Spread operator가 있다.

let arr = [1,2,3];
let arr2 = [4,5];
let arr3 = [...arr, ...arr2]
console.log(arr3 //[1, 2, 3, 4, 5]

를 해보면 결과는 [1, 2, 3, 4, 5] 로 나온다.


설명 참조

https://sgcomputer.tistory.com/152

 

자바스크립트 함수와 매개변수, 인수

매개변수의 타입 자바 스크립트에서 함수를 정의할 때 매개 변수의 타입은 따로 명시하지 않는다. 어차피 변수 자체도 타입을 명시하지 않기 때문에 전달되는 파라미터 값도 데이터를 가려받진

sgcomputer.tistory.com

 

728x90
728x90

startWith()

str.startWith(searchString, position)
어떤 문자열이 특정 문자로 시작하는지 확인하여 결과를 true 혹은 false로 반환

var name = '김동현';

console.log(name.startsWith('김')); //name의 0번째 자리가 '김'인지
console.log(name.startsWith('동',1)); //name의 1번째 자리가 '동'인지


some()

조건에 true가 1개라도 있으면 true, 없으면 false

var nameArray = [
    '김동현', '강호동', '박민기',
    '고민정', '황철순', '지피티',
    '강경원', '박동현', '안철수',
    '김민수', '이준기', '박동훈'
]

var tempData = nameArray.some((item)=>{ //nameArray중에 '김'으로 시작하는 데이터가 있나?
    return item.startsWith('김')
    });

console.log(tempData);

 


every()

모든 데이터가 조건에 맞는지 확인
예를들면 아래 데이터 중에 모든 사람이 김씨인가? => false

var nameArray = [
    '김동현', '강호동', '박민기',
    '고민정', '황철순', '지피티',
    '강경원', '박동현', '안철수',
    '김민수', '이준기', '박동훈'
]

var tempData = nameArray.every((item)=>{  //모든 데이터가 '김'으로 시작하는가?
	return item.startsWith('김')
    });

var tempData2 = nameArray.every((item)=>{ //모든 데이터의 길이가 0보다 큰가?
	return item.length > 0
    });

console.log(tempData); //false
console.log(tempData2); //true


forEach()

for문처럼 배열에 있는걸 다 돌린다.
근데 멈추는거 없고 그냥 다 돌려버린다.

var nameArray = [
    '김동현', '강호동', '박민기',
 ]
nameArray.forEach((item, index)=>{
    console.log(item, index);
});


 

map()

map는 array를 리턴한다.

var nameArray = [
    '김동현', '강호동', '박민기',
    '고민정', '황철순', '지피티',
    '강경원', '박동현', '안철수',
    '김민수', '이준기', '박동훈'
 ]
 
var tempData = nameArray.map((item)=>{
    return item
})

console.log(tempData);

ex) 배열안의 여러 데이터 중에서 예를들어 이름이라던지, 나이라던지 하나의 데이터만 뽑아와서 배열을 만들 수 있다.
엄청 많은 데이터 중에서 원하는 데이터만 뽑아서 새로 데이터를 만들어서 작업 가능


filter()

var nameArray = [
    '김동현', '강호동', '박민기',
    '고민정', '황철순', '지피티',
    '강경원', '박동현', '안철수',
    '김민수', '이준기', '박동훈'
 ]
var tempData = nameArray.filter((item)=>{
    return item.startsWith('김');
})

console.log(tempData);


 

728x90

+ Recent posts