diff --git a/1 WEEK/core/1 week.md b/1 WEEK/core/1 week.md index 283a343d..e016776a 100644 --- a/1 WEEK/core/1 week.md +++ b/1 WEEK/core/1 week.md @@ -445,6 +445,9 @@ class OrderServiceTest { } ``` ## HOME WORK -1. 위 코드의 핵심은 무엇일까요? -2. 위 코드의 문제점은 무엇일까요? -3. 그 해결 방법은 무엇일까요? +1. 위 코드의 핵심은 무엇일까요?
+ -- 관심사 분리, 추상화 클래스에 의존이 핵심이라 생각됩니다.
+2. 위 코드의 문제점은 무엇일까요?
+ -- 할인 정책이나, 데이터 저장 부분이 바뀌었을 때, 그와 관련된 모든 코드를 수정해야한다는 점과 Order 클래스가 2개 이상의 책임을 지고 있는것이 문제점입니다.
+3. 그 해결 방법은 무엇일까요?
+ -- 의존성을 주입해주는 클래스를 따로 만들어주고, Order 클래스는 책임을 1가지만 지도록 calculatePrice() 메서드를 빼주는 것으로 해결해야 합니다.
diff --git a/10 WEEK/students/.gitignore b/10 WEEK/students/.gitignore new file mode 100644 index 00000000..c2065bc2 --- /dev/null +++ b/10 WEEK/students/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/10 WEEK/students/build.gradle b/10 WEEK/students/build.gradle new file mode 100644 index 00000000..59323230 --- /dev/null +++ b/10 WEEK/students/build.gradle @@ -0,0 +1,34 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.2.2' + id 'io.spring.dependency-management' version '1.1.4' +} + +group = 'yebin' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '17' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/10 WEEK/students/gradle/wrapper/gradle-wrapper.jar b/10 WEEK/students/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..d64cd491 Binary files /dev/null and b/10 WEEK/students/gradle/wrapper/gradle-wrapper.jar differ diff --git a/10 WEEK/students/gradle/wrapper/gradle-wrapper.properties b/10 WEEK/students/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..1af9e093 --- /dev/null +++ b/10 WEEK/students/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/10 WEEK/students/gradlew b/10 WEEK/students/gradlew new file mode 100644 index 00000000..1aa94a42 --- /dev/null +++ b/10 WEEK/students/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/10 WEEK/students/gradlew.bat b/10 WEEK/students/gradlew.bat new file mode 100644 index 00000000..93e3f59f --- /dev/null +++ b/10 WEEK/students/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/10 WEEK/students/settings.gradle b/10 WEEK/students/settings.gradle new file mode 100644 index 00000000..6193f06f --- /dev/null +++ b/10 WEEK/students/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'students' diff --git a/10 WEEK/students/src/main/java/yebin/students/StudentRepository.java b/10 WEEK/students/src/main/java/yebin/students/StudentRepository.java new file mode 100644 index 00000000..f48bc309 --- /dev/null +++ b/10 WEEK/students/src/main/java/yebin/students/StudentRepository.java @@ -0,0 +1,47 @@ +package yebin.students; + +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +public class StudentRepository { + private static final Map store = new HashMap<>(); + + + public Students save(Students student){ + store.put(student.getId(), student); + return student; + } + + public Students findById(Long id){ + return store.get(id); + } + + public List findAll(){ + return new ArrayList<>(store.values()); + } + + public void update(Long id, Students updateStudent){ + //DB 에서 회원 정보를 찾는다 [ 이미 별도 메서드로 구분 되어 있음 ] 추상화 레벨 2 + Students findStudent = store.get(id); + //Entity 정보를 수정한다. : 추상화 레벨 2 + findStudent.setName(updateStudent.getName()); + findStudent.setGrade(updateStudent.getGrade()); + findStudent.setMajor(updateStudent.getMajor()); + //DB 에 새로운 정보를 저장한다. : [ 이미 별도 메서드로 구분 되어 있음 ] 추상화 레벨 2 + save(findStudent); + } + + + public void delete(Long id){ + store.remove(id); + } + + public void clearStore(){ + store.clear(); + } +} diff --git a/10 WEEK/students/src/main/java/yebin/students/StudentService.java b/10 WEEK/students/src/main/java/yebin/students/StudentService.java new file mode 100644 index 00000000..00e40cfa --- /dev/null +++ b/10 WEEK/students/src/main/java/yebin/students/StudentService.java @@ -0,0 +1,11 @@ +package yebin.students; + +import java.util.List; + +public interface StudentService { + public void join(Students student); + public Students showStudentInForById(Long studentId); + public void deleteStudentInFortById(Long studentId); + public void updateStudentInForById(Long studentId, Students updateStudent); + public boolean multiDeleteStudentInForById(List studentId); +} diff --git a/10 WEEK/students/src/main/java/yebin/students/StudentServiceImpl.java b/10 WEEK/students/src/main/java/yebin/students/StudentServiceImpl.java new file mode 100644 index 00000000..2eb68070 --- /dev/null +++ b/10 WEEK/students/src/main/java/yebin/students/StudentServiceImpl.java @@ -0,0 +1,40 @@ +package yebin.students; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class StudentServiceImpl implements StudentService{ + private final StudentRepository studentRepository; + @Override + public void join(Students student) { + studentRepository.save(student); + } + + @Override + public Students showStudentInForById(Long studentId) { + return studentRepository.findById(studentId); + } + + @Override + public void deleteStudentInFortById(Long studentId) { + studentRepository.delete(studentId); + } + + @Override + public void updateStudentInForById(Long studentId, Students updateStudent) { + studentRepository.update(studentId, updateStudent); + } + + @Override + public boolean multiDeleteStudentInForById(List studentId){ + for (Long id : studentId) { + studentRepository.delete(id); + return true; + } + return false; + } +} diff --git a/10 WEEK/students/src/main/java/yebin/students/Students.java b/10 WEEK/students/src/main/java/yebin/students/Students.java new file mode 100644 index 00000000..206d6785 --- /dev/null +++ b/10 WEEK/students/src/main/java/yebin/students/Students.java @@ -0,0 +1,21 @@ +package yebin.students; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Students { + private String name; + private Long id; + private Integer grade; + private String major; + + public Students(String name, Long id,Integer grade, String major){ + this.name = name; + this.id = id; + this.grade = grade; + this.major = major; + } +} diff --git a/10 WEEK/students/src/main/java/yebin/students/StudentsApplication.java b/10 WEEK/students/src/main/java/yebin/students/StudentsApplication.java new file mode 100644 index 00000000..87fd4b25 --- /dev/null +++ b/10 WEEK/students/src/main/java/yebin/students/StudentsApplication.java @@ -0,0 +1,13 @@ +package yebin.students; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StudentsApplication { + + public static void main(String[] args) { + SpringApplication.run(StudentsApplication.class, args); + } + +} diff --git a/10 WEEK/students/src/main/resources/application.properties b/10 WEEK/students/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/10 WEEK/students/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/10 WEEK/students/src/test/java/yebin/students/StudentRepositoryTest.java b/10 WEEK/students/src/test/java/yebin/students/StudentRepositoryTest.java new file mode 100644 index 00000000..137a3926 --- /dev/null +++ b/10 WEEK/students/src/test/java/yebin/students/StudentRepositoryTest.java @@ -0,0 +1,70 @@ +package yebin.students; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class StudentRepositoryTest { + StudentRepository studentRepository = new StudentRepository(); + + @AfterEach + void afterEach(){ + studentRepository.clearStore(); + } + + @Test + void save(){ + //given + Students student = new Students("yebin", 4, "소프트웨어학과"); + //when + Students saveStudent = studentRepository.save(student); + //then + Students findStudent = studentRepository.findById(student.getId()); + Assertions.assertThat(findStudent).isEqualTo(saveStudent); + } + + @Test + void findAll(){ + //given + Students student1 = new Students("yebin", 4, "소프트웨어학과"); + Students student2 = new Students("son", 4, "소프트웨어학과"); + studentRepository.save(student1); + studentRepository.save(student2); + //when + List students = studentRepository.findAll(); + //then + Assertions.assertThat(students.size()).isEqualTo(2); + Assertions.assertThat(students).contains(student1,student2); + } + + @Test + void update(){ + //given + Students student = new Students("yebin", 4, "소프트웨어학과"); + Students savedStudent = studentRepository.save(student); + Long studentId = savedStudent.getId(); + //when + Students updateStudent = new Students("son", 2, "전자공학과"); + studentRepository.update(studentId,updateStudent); + Students findStudent = studentRepository.findById(studentId); + //then + Assertions.assertThat(findStudent.getName()).isEqualTo(updateStudent.getName()); + Assertions.assertThat(findStudent.getGrade()).isEqualTo(updateStudent.getGrade()); + Assertions.assertThat(findStudent.getMajor()).isEqualTo(updateStudent.getMajor()); + } + + @Test + void delete(){ + //given + Students student = new Students("yebin", 4, "소프트웨어학과"); + Students savedStudent = studentRepository.save(student); + Long studentId = savedStudent.getId(); + //when + studentRepository.delete(studentId); + List students = studentRepository.findAll(); + //then + Assertions.assertThat(students.size()).isEqualTo(0); + } +} diff --git a/10 WEEK/students/src/test/java/yebin/students/StudentsApplicationTests.java b/10 WEEK/students/src/test/java/yebin/students/StudentsApplicationTests.java new file mode 100644 index 00000000..4dd4e763 --- /dev/null +++ b/10 WEEK/students/src/test/java/yebin/students/StudentsApplicationTests.java @@ -0,0 +1,13 @@ +package yebin.students; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class StudentsApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/12 WEEK/student/student/.gitignore b/12 WEEK/student/student/.gitignore new file mode 100644 index 00000000..c2065bc2 --- /dev/null +++ b/12 WEEK/student/student/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/12 WEEK/student/student/build.gradle b/12 WEEK/student/student/build.gradle new file mode 100644 index 00000000..c7415fe4 --- /dev/null +++ b/12 WEEK/student/student/build.gradle @@ -0,0 +1,34 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.2.2' + id 'io.spring.dependency-management' version '1.1.4' +} + +group = 'student' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '17' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/12 WEEK/student/student/gradle/wrapper/gradle-wrapper.jar b/12 WEEK/student/student/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..d64cd491 Binary files /dev/null and b/12 WEEK/student/student/gradle/wrapper/gradle-wrapper.jar differ diff --git a/12 WEEK/student/student/gradle/wrapper/gradle-wrapper.properties b/12 WEEK/student/student/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..1af9e093 --- /dev/null +++ b/12 WEEK/student/student/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/12 WEEK/student/student/gradlew b/12 WEEK/student/student/gradlew new file mode 100644 index 00000000..1aa94a42 --- /dev/null +++ b/12 WEEK/student/student/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/12 WEEK/student/student/gradlew.bat b/12 WEEK/student/student/gradlew.bat new file mode 100644 index 00000000..93e3f59f --- /dev/null +++ b/12 WEEK/student/student/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/12 WEEK/student/student/settings.gradle b/12 WEEK/student/student/settings.gradle new file mode 100644 index 00000000..d3e43d80 --- /dev/null +++ b/12 WEEK/student/student/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'student' diff --git a/12 WEEK/student/student/src/main/java/student/student/ENUM/Grade.java b/12 WEEK/student/student/src/main/java/student/student/ENUM/Grade.java new file mode 100644 index 00000000..c29e2777 --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/ENUM/Grade.java @@ -0,0 +1,5 @@ +package student.student.ENUM; + +public enum Grade { + freshman, sophomore, junior, senior, the_5th +} diff --git a/12 WEEK/student/student/src/main/java/student/student/ENUM/Major.java b/12 WEEK/student/student/src/main/java/student/student/ENUM/Major.java new file mode 100644 index 00000000..d6f36211 --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/ENUM/Major.java @@ -0,0 +1,5 @@ +package student.student.ENUM; + +public enum Major { + 소프트웨어학과, 컴퓨터공학과, 산업디자인학과 +} diff --git a/12 WEEK/student/student/src/main/java/student/student/ENUM/Semester.java b/12 WEEK/student/student/src/main/java/student/student/ENUM/Semester.java new file mode 100644 index 00000000..cfa92bea --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/ENUM/Semester.java @@ -0,0 +1,5 @@ +package student.student.ENUM; + +public enum Semester { + first, second +} diff --git a/12 WEEK/student/student/src/main/java/student/student/Student.java b/12 WEEK/student/student/src/main/java/student/student/Student.java new file mode 100644 index 00000000..4e20127c --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/Student.java @@ -0,0 +1,50 @@ +package student.student; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import student.student.ENUM.Grade; +import student.student.ENUM.Major; +import student.student.ENUM.Semester; + +@Getter +@Setter +public class Student { + private Long id; + private Grade grade; + private String name; + private String brith; + private Integer birthYear; + private Integer birthMonth; + private Integer birthMonthOfDay; + private Major major; + private Semester semester; + private String address; + + public Student(Long id, Grade grade, String name, String brith, Integer birthYear, Integer birthMonth, Integer birthMonthOfDay, Major major, Semester semester, String address) { + this.id = id; + this.grade = grade; + this.name = name; + this.brith = brith; + this.birthYear = birthYear; + this.birthMonth = birthMonth; + this.birthMonthOfDay = birthMonthOfDay; + this.major = major; + this.semester = semester; + this.address = address; + } + + public void signUpFormData(Long id, String name, String birth, Semester semester, String address, Grade grade){ + this.id = id; + this.name = name; + this.brith = birth; + this.semester = semester; + this.address = address; + this.grade = grade; + } + + public void updateFormData(String name, String address){ + this.name = name; + this.address = address; + } +} \ No newline at end of file diff --git a/12 WEEK/student/student/src/main/java/student/student/StudentApplication.java b/12 WEEK/student/student/src/main/java/student/student/StudentApplication.java new file mode 100644 index 00000000..f764084d --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/StudentApplication.java @@ -0,0 +1,13 @@ +package student.student; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StudentApplication { + + public static void main(String[] args) { + SpringApplication.run(StudentApplication.class, args); + } + +} diff --git a/12 WEEK/student/student/src/main/java/student/student/controller/StudentController.java b/12 WEEK/student/student/src/main/java/student/student/controller/StudentController.java new file mode 100644 index 00000000..80717069 --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/controller/StudentController.java @@ -0,0 +1,45 @@ +package student.student.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import student.student.Student; +import student.student.service.StudentService; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/student") +public class StudentController { + private final StudentService studentService; + + @PostMapping + public String addStudent(@ModelAttribute Student student){ + Object saveStudentData = studentService.saveStudent(student); + return "/addStudentForm"; + } + + @GetMapping("/{studentId}") + public String showStudentByStudentId(@PathVariable Long studentId, Model model){ + Object findStudent = studentService.showStudentByStudentId(studentId); + model.addAttribute("findStudent",findStudent); + return "/findStudentForm"; + } + + @GetMapping + public String showAllStudents(Model model){ + List students = studentService.showAllStudents(); + model.addAttribute("findAllStudents",students); + return "/findStudentForm"; + } + + @PatchMapping("/{studentId}") + public String updateStudentByStudentId(@PathVariable Long studentId, @ModelAttribute Student updateStudent){ + studentService.updateStudentByStudentId(studentId, updateStudent); + return "/updateStudentForm"; + } + + +} diff --git a/12 WEEK/student/student/src/main/java/student/student/repository/StudentRepository.java b/12 WEEK/student/student/src/main/java/student/student/repository/StudentRepository.java new file mode 100644 index 00000000..33b47f59 --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/repository/StudentRepository.java @@ -0,0 +1,39 @@ +package student.student.repository; + +import org.springframework.stereotype.Repository; +import student.student.Student; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +public class StudentRepository { + private static final Map store = new HashMap<>(); + + public Student save(Student student){ + store.put(student.getId(), student); + return student; + } + + public Student findById(Long studentId){ + return store.get(studentId); + } + + public List findAll(){ + return new ArrayList<>(store.values()); + } + + public void update(Long studentId, Student updateStudent){ + Student findStudent = findById(studentId); + updateStudentInformation(findStudent,updateStudent); + save(findStudent); + } + + private void updateStudentInformation(Student findStudent, Student updateStudent){ + findStudent.setName(updateStudent.getName()); + findStudent.setAddress(updateStudent.getAddress()); + } +} + diff --git a/12 WEEK/student/student/src/main/java/student/student/service/StudentService.java b/12 WEEK/student/student/src/main/java/student/student/service/StudentService.java new file mode 100644 index 00000000..11adbcf3 --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/service/StudentService.java @@ -0,0 +1,12 @@ +package student.student.service; + +import student.student.Student; + +import java.util.List; + +public interface StudentService { + Object saveStudent(Student student); + Student showStudentByStudentId(Long studentId); + List showAllStudents(); + Object updateStudentByStudentId(Long studentId, Student updateStudent); +} diff --git a/12 WEEK/student/student/src/main/java/student/student/service/StudentServiceImpl.java b/12 WEEK/student/student/src/main/java/student/student/service/StudentServiceImpl.java new file mode 100644 index 00000000..513a0619 --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/service/StudentServiceImpl.java @@ -0,0 +1,84 @@ +package student.student.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import student.student.Student; +import student.student.repository.StudentRepository; +import student.student.validation.ValidateStudent; + +import java.util.List; +import java.util.Objects; + +@Service +@RequiredArgsConstructor +public class StudentServiceImpl implements StudentService{ + private StudentRepository studentRepository; + private ValidateStudent validateStudent; + @Override + public Object saveStudent(Student student) { + Student findStudent = studentRepository.findById(student.getId()); + // 저장하려는 학생 정보가 이미 있다면 해당 학생 정보 반환 + if (!Objects.isNull(findStudent)){ + return findStudent; + } + // 저장하려는 학생의 학번이 요구사항을 충족하지 못했다면 학번 반환 + if(!validateStudent.validateStudentId(student.getId())){ + return student.getId(); + } + // 저장하려는 학생의 이름이 요구사항을 충족하지 못했다면 이름 반환 + if(!validateStudent.validateStudentName(student.getName())){ + return student.getName(); + } + // 저장하려는 학생의 학과가 요구사항을 충족하지 못했다면 학과 반환 + if(!validateStudent.validateMajor(student.getMajor())){ + return student.getMajor(); + } + // 저장하려는 학생의 학기가 요구사항을 충족하지 못했다면 학기 반환 + if(!validateStudent.validateSemester(student.getSemester())){ + return student.getSemester(); + } + // 저장하려는 학생의 학년이 요구사항을 충족하지 못했다면 학년 반환 + if(!validateStudent.validateGrade(student.getGrade())){ + return student.getGrade(); + } + + return studentRepository.save(student); + } + + @Override + public Student showStudentByStudentId(Long studentId) { + Student findStudent = studentRepository.findById(studentId); + // 찾으려는 학생의 정보가 없다면 null 반환? + if(Objects.isNull(findStudent)){ + return null; + } + + return findStudent; + } + + @Override + public List showAllStudents() { + List students = studentRepository.findAll(); + // 찾으려는 학생의 정보가 없다면 null 반환 + if (Objects.isNull(students)){ + return null; + } + + return studentRepository.findAll(); + } + + @Override + public Object updateStudentByStudentId(Long studentId, Student updateStudent) { + Student findStudent = studentRepository.findById(studentId); + if(Objects.isNull(findStudent)){ + return null; + } + // 수정하려는 학생의 이름이 요구사항을 충족하지 못했다면 이름 반환 + if(validateStudent.validateStudentName(updateStudent.getName())){ + return updateStudent.getName(); + } + + studentRepository.update(studentId,updateStudent); + return updateStudent; + } +} diff --git a/12 WEEK/student/student/src/main/java/student/student/validation/ValidateStudent.java b/12 WEEK/student/student/src/main/java/student/student/validation/ValidateStudent.java new file mode 100644 index 00000000..a4871851 --- /dev/null +++ b/12 WEEK/student/student/src/main/java/student/student/validation/ValidateStudent.java @@ -0,0 +1,55 @@ +package student.student.validation; + +import student.student.ENUM.Grade; +import student.student.ENUM.Major; +import student.student.ENUM.Semester; +import student.student.Student; + +import java.util.regex.Pattern; + +public class ValidateStudent { + public boolean validateStudentId(Long studentId){ + if(studentId.SIZE != 7){ + return false; + } + if(!Pattern.matches("[0-9+]",String.valueOf(studentId))){ + return false; + } + + return true; + } + + public boolean validateStudentName(String studentName){ + if(!Pattern.matches("^[ㄱ-ㅎ가-힣]*$",studentName)){ + return false; + } + if(studentName.length() >= 2 && studentName.length() <= 7){ + return false; + } + return true; + } + + public boolean validateMajor(Major studentMajor){ + // [ 소프트웨어, 컴퓨터공학, 산업디자인학과 외 금지 ] 이 의도를 표현하고 싶었으나 이렇게 하는건 아닌것 같은데.. + if (studentMajor != Major.산업디자인학과 || studentMajor != Major.컴퓨터공학과 || studentMajor != Major.소프트웨어학과){ + return false; + } + return true; + } + + public boolean validateSemester(Semester studentSemester){ + // 위와 동일,, + if(studentSemester != Semester.first || studentSemester != Semester.second){ + return false; + } + return true; + } + + public boolean validateGrade(Grade studentGrade){ + // 위와 동일,, + if(studentGrade != Grade.freshman || studentGrade != Grade.sophomore || studentGrade != Grade.junior || studentGrade != Grade.senior || studentGrade !=Grade.the_5th){ + return false; + } + return true; + } +} diff --git a/12 WEEK/student/student/src/main/resources/application.properties b/12 WEEK/student/student/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/12 WEEK/student/student/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/12 WEEK/student/student/src/test/java/student/student/StudentApplicationTests.java b/12 WEEK/student/student/src/test/java/student/student/StudentApplicationTests.java new file mode 100644 index 00000000..cace9524 --- /dev/null +++ b/12 WEEK/student/student/src/test/java/student/student/StudentApplicationTests.java @@ -0,0 +1,13 @@ +package student.student; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class StudentApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/2 WEEK/SON/ANSWER.md b/2 WEEK/SON/ANSWER.md index 066e2c2a..1cf0c1b1 100644 --- a/2 WEEK/SON/ANSWER.md +++ b/2 WEEK/SON/ANSWER.md @@ -44,16 +44,37 @@ https://agilemanifesto.org/iso/ko/manifesto.html
--- ## 주요 이론 요약 - -Please provide a summary of your main theory here. +Object Oriented Programming 설계 원칙
+
+OOP의 5원칙 ( SOLID )
+SRP ( Single Responsibility Prindiple ) : 한 클래스는 하나의 책임만 가져야 한다.
+OCP ( Open-Closed Prindiple ) : 확장에는 열려있으나, 변경에는 닫혀있어야한다.
+LSP ( Liskov's Substitution Principle ) : 하위객체는 상위객체와 교체할 수 있어야한다.
+ISP ( Interface Segregation Principle ) : 관심사에 맞게 인터페이스를 분리해야한다.
+DIP ( Dependency Inversion Principle ) : 구체화에 의존하지말고 추상화에 의존해야한다.
+
+OOP의 4가지 특징
+1. 캡슐화 2. 상속 3. 추상화 4. 다형성 ## ISSUE -Please enter your issue details here. - +SRP 위반 ---
+ Order 클래스 - calculatedPrice() 메서드가 Order 클래스내에 있으면 Order 클래스가 여러개의 책임을 갖으므로 SRP위반이라 생각됩니다.
+OCP 위반 ---
+ OrderServiceImpl 클래스 - memeberRepository와 discountPolicy를 직접 생성해주면 나중에 정책이 바뀌었을 때, + 이러한 변수를 선언한 코드들을 모두 수정해주어야하므로 OCP위반이라 생각됩니다.
+LSP 위반 ---
+
+ISP 위반 ---
+
+DIP 위반 ---
+
## Solution -Please describe your solution in detail here. +SRP 위반 ---
+ Order 클래스 - calculatedPrice()를 Order 클래스에서 빼내어 OrderService 클래스로 옮겨 책임을 한가지만 갖도록 해줍니다.
+OCP 위반 ---
+ OrderServiceImplt 클래스 - 의존성을 주입해주는 클래스를 새로 만들어 정책이 바뀌었을 시, 그 클래스만 수정하면 되도록 만들어줍니다.
## About diff --git a/2 WEEK/SON/yebin/.gitignore b/2 WEEK/SON/yebin/.gitignore new file mode 100644 index 00000000..c2065bc2 --- /dev/null +++ b/2 WEEK/SON/yebin/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/2 WEEK/SON/yebin/build.gradle b/2 WEEK/SON/yebin/build.gradle new file mode 100644 index 00000000..13d739db --- /dev/null +++ b/2 WEEK/SON/yebin/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.17' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +group = 'com.yebin' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '11' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('bootBuildImage') { + builder = 'paketobuildpacks/builder-jammy-base:latest' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/2 WEEK/SON/yebin/gradle/wrapper/gradle-wrapper.jar b/2 WEEK/SON/yebin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..7f93135c Binary files /dev/null and b/2 WEEK/SON/yebin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/2 WEEK/SON/yebin/gradle/wrapper/gradle-wrapper.properties b/2 WEEK/SON/yebin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3fa8f862 --- /dev/null +++ b/2 WEEK/SON/yebin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/2 WEEK/SON/yebin/gradlew b/2 WEEK/SON/yebin/gradlew new file mode 100644 index 00000000..1aa94a42 --- /dev/null +++ b/2 WEEK/SON/yebin/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/2 WEEK/SON/yebin/gradlew.bat b/2 WEEK/SON/yebin/gradlew.bat new file mode 100644 index 00000000..93e3f59f --- /dev/null +++ b/2 WEEK/SON/yebin/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/2 WEEK/SON/yebin/settings.gradle b/2 WEEK/SON/yebin/settings.gradle new file mode 100644 index 00000000..2e756485 --- /dev/null +++ b/2 WEEK/SON/yebin/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'yebin' diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/MemberApp.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/MemberApp.java new file mode 100644 index 00000000..d08a0e36 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/MemberApp.java @@ -0,0 +1,25 @@ +package com.yebin.yebin; + +import com.yebin.yebin.dependency.AppConfig; +import com.yebin.yebin.member.Grade; +import com.yebin.yebin.member.Member; +import com.yebin.yebin.member.MemberService; +import com.yebin.yebin.member.MemberServiceImpl; + +public class MemberApp { + public static void main(String[] args) { + AppConfig appConfig = new AppConfig(); + MemberService memberService =appConfig.memberService(); + + Member member = new Member("memberA", Grade.VIP); + + memberService.join(member); + + Member findMember = memberService.findMember(1L); + + System.out.println("member = " + member.getName()); + System.out.println("findMember = " + findMember.getName()); + + + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/OrderApp.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/OrderApp.java new file mode 100644 index 00000000..dfba847c --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/OrderApp.java @@ -0,0 +1,26 @@ +package com.yebin.yebin; + +import com.yebin.yebin.dependency.AppConfig; +import com.yebin.yebin.member.Grade; +import com.yebin.yebin.member.Member; +import com.yebin.yebin.member.MemberService; +import com.yebin.yebin.member.MemberServiceImpl; +import com.yebin.yebin.order.Order; +import com.yebin.yebin.order.OrderService; +import com.yebin.yebin.order.OrderServiceImpl; + +public class OrderApp { + public static void main(String[] args) { + AppConfig appConfig = new AppConfig(); + MemberService memberService = appConfig.memberService(); + OrderService orderService = appConfig.orderService(); + + Member member = new Member("memberA", Grade.VIP); + memberService.join(member); + + Order order = orderService.createOrder(member.getId(),"itemA",10000); + + System.out.println("order = " + order); + + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/YebinApplication.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/YebinApplication.java new file mode 100644 index 00000000..c14d586d --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/YebinApplication.java @@ -0,0 +1,13 @@ +package com.yebin.yebin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class YebinApplication { + + public static void main(String[] args) { + SpringApplication.run(YebinApplication.class, args); + } + +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/dependency/AppConfig.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/dependency/AppConfig.java new file mode 100644 index 00000000..220170b0 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/dependency/AppConfig.java @@ -0,0 +1,37 @@ +package com.yebin.yebin.dependency; + +import com.yebin.yebin.discount.DiscountPolicy; +import com.yebin.yebin.discount.RateDiscountPolicy; +import com.yebin.yebin.member.MemberRepository; +import com.yebin.yebin.member.MemberService; +import com.yebin.yebin.member.MemberServiceImpl; +import com.yebin.yebin.member.MemoryMemberRepository; +import com.yebin.yebin.order.OrderService; +import com.yebin.yebin.order.OrderServiceImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AppConfig { + @Bean + public DiscountPolicy discountPolicy(){ + // 할인 정책이 바뀌면 이 부분만 바꿔주면 된다. + return new RateDiscountPolicy(); + } + + @Bean + public MemberRepository memberRepository(){ + // DB 연결하면 이 부분만 바꿔주면 된다. + return new MemoryMemberRepository(); + } + + @Bean + public MemberService memberService(){ + return new MemberServiceImpl(memberRepository()); + } + + @Bean + public OrderService orderService(){ + return new OrderServiceImpl(memberRepository(),discountPolicy()); + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/DiscountPolicy.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/DiscountPolicy.java new file mode 100644 index 00000000..ed10ed1b --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/DiscountPolicy.java @@ -0,0 +1,7 @@ +package com.yebin.yebin.discount; + +import com.yebin.yebin.member.Member; + +public interface DiscountPolicy { + float discount(Member member, int price); +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/FixDiscountPolicy.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/FixDiscountPolicy.java new file mode 100644 index 00000000..5c2d3118 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/FixDiscountPolicy.java @@ -0,0 +1,19 @@ +package com.yebin.yebin.discount; + +import com.yebin.yebin.member.Grade; +import com.yebin.yebin.member.Member; + +public class FixDiscountPolicy implements DiscountPolicy{ + private int discountFixAmount = 1000; + + @Override + public float discount(Member member, int price) { + + if (member.getGrade() == Grade.VIP) { + return discountFixAmount; + }else { + return 0; + } + + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/RateDiscountPolicy.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/RateDiscountPolicy.java new file mode 100644 index 00000000..3a89ab08 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/discount/RateDiscountPolicy.java @@ -0,0 +1,18 @@ +package com.yebin.yebin.discount; + +import com.yebin.yebin.member.Grade; +import com.yebin.yebin.member.Member; +import org.springframework.stereotype.Component; + + +public class RateDiscountPolicy implements DiscountPolicy{ + private float discountRate = 10; + @Override + public float discount(Member member, int price) { + if (member.getGrade() == Grade.VIP){ + return price * (discountRate/100); + } + + return 0; + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/Grade.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/Grade.java new file mode 100644 index 00000000..d35ba28c --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/Grade.java @@ -0,0 +1,6 @@ +package com.yebin.yebin.member; + +public enum Grade { + BASIC, + VIP +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/Member.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/Member.java new file mode 100644 index 00000000..85db9daa --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/Member.java @@ -0,0 +1,20 @@ +package com.yebin.yebin.member; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Member { + private Long id; + private String name; + private Grade grade; + + public Member( String name, Grade grade) { + this.name = name; + this.grade = grade; + } + + + +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberRepository.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberRepository.java new file mode 100644 index 00000000..bb51ae85 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberRepository.java @@ -0,0 +1,7 @@ +package com.yebin.yebin.member; + +public interface MemberRepository { + void save(Member member); + + Member findById(Long memberId); +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberService.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberService.java new file mode 100644 index 00000000..49a89ab7 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberService.java @@ -0,0 +1,7 @@ +package com.yebin.yebin.member; + +public interface MemberService { + void join(Member member); + + Member findMember(Long memberId); +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberServiceImpl.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberServiceImpl.java new file mode 100644 index 00000000..de7db79f --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemberServiceImpl.java @@ -0,0 +1,27 @@ +package com.yebin.yebin.member; + +import com.yebin.yebin.dependency.AppConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + + +public class MemberServiceImpl implements MemberService{ + + private final MemberRepository memberRepository; + + + public MemberServiceImpl(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + @Override + public void join(Member member) { + memberRepository.save(member); + } + + @Override + public Member findMember(Long memberId) { + return memberRepository.findById(memberId); + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemoryMemberRepository.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemoryMemberRepository.java new file mode 100644 index 00000000..7689a99f --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/member/MemoryMemberRepository.java @@ -0,0 +1,22 @@ +package com.yebin.yebin.member; + +import org.springframework.stereotype.Repository; + +import java.util.HashMap; +import java.util.Map; + +public class MemoryMemberRepository implements MemberRepository{ + private static Map store = new HashMap<>(); + private static long SEQUENCE = 0L; + + @Override + public void save(Member member) { + member.setId(++SEQUENCE); + store.put(member.getId(),member); + } + + @Override + public Member findById(Long memberId) { + return store.get(memberId); + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/Order.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/Order.java new file mode 100644 index 00000000..735931ef --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/Order.java @@ -0,0 +1,29 @@ +package com.yebin.yebin.order; + +public class Order { + private Long memberId; + private String itemName; + private int itemPrice; + private float discountPrice; + + public Order(Long memberId, String itemName, int itemPrice, float discountPrice){ + this.memberId = memberId; + this.itemName = itemName; + this.itemPrice = itemPrice; + this.discountPrice = discountPrice; + } + + public float getDiscountPrice(){ + return discountPrice; + } + + @Override + public String toString() { + return "Order{" + + "memberId=" + memberId + + ", itemName='" + itemName + '\'' + + ", itemPrice=" + itemPrice + + ", discountPrice=" + discountPrice + + '}'; + } +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/OrderService.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/OrderService.java new file mode 100644 index 00000000..bd7ebbb5 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/OrderService.java @@ -0,0 +1,6 @@ +package com.yebin.yebin.order; + +public interface OrderService { + Order createOrder(Long memberId, String itemName, int itemPrice); + float calculatePrice(int itemPrice, float discountPrice); +} diff --git a/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/OrderServiceImpl.java b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/OrderServiceImpl.java new file mode 100644 index 00000000..d56f6f6e --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/java/com/yebin/yebin/order/OrderServiceImpl.java @@ -0,0 +1,32 @@ +package com.yebin.yebin.order; + +import com.yebin.yebin.dependency.AppConfig; +import com.yebin.yebin.discount.DiscountPolicy; +import com.yebin.yebin.member.Member; +import com.yebin.yebin.member.MemberRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + + +public class OrderServiceImpl implements OrderService{ + private final MemberRepository memberRepository; + private final DiscountPolicy discountPolicy; + + + public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy){ + this.memberRepository = memberRepository; + this.discountPolicy = discountPolicy; + } + + @Override + public Order createOrder(Long memberId, String itemName, int itemPrice) { + Member member = memberRepository.findById(memberId); + float discountPrice = discountPolicy.discount(member,itemPrice); + return new Order(memberId, itemName, itemPrice, discountPrice); + } + + @Override + public float calculatePrice(int itemPrice, float discountPrice) { + return itemPrice - discountPrice; + } +} diff --git a/2 WEEK/SON/yebin/src/main/resources/application.properties b/2 WEEK/SON/yebin/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/2 WEEK/SON/yebin/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/2 WEEK/SON/yebin/src/test/java/com/yebin/yebin/YebinApplicationTests.java b/2 WEEK/SON/yebin/src/test/java/com/yebin/yebin/YebinApplicationTests.java new file mode 100644 index 00000000..99fb928e --- /dev/null +++ b/2 WEEK/SON/yebin/src/test/java/com/yebin/yebin/YebinApplicationTests.java @@ -0,0 +1,13 @@ +package com.yebin.yebin; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class YebinApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/4 WEEK/item-service/.gitignore b/4 WEEK/item-service/.gitignore new file mode 100644 index 00000000..c2065bc2 --- /dev/null +++ b/4 WEEK/item-service/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/4 WEEK/item-service/build.gradle b/4 WEEK/item-service/build.gradle new file mode 100644 index 00000000..34550a7d --- /dev/null +++ b/4 WEEK/item-service/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.1.6' + id 'io.spring.dependency-management' version '1.1.4' +} + +group = 'hello' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '17' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('bootBuildImage') { + builder = 'paketobuildpacks/builder-jammy-base:latest' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/4 WEEK/item-service/gradle/wrapper/gradle-wrapper.jar b/4 WEEK/item-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..7f93135c Binary files /dev/null and b/4 WEEK/item-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/4 WEEK/item-service/gradle/wrapper/gradle-wrapper.properties b/4 WEEK/item-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3fa8f862 --- /dev/null +++ b/4 WEEK/item-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/4 WEEK/item-service/gradlew b/4 WEEK/item-service/gradlew new file mode 100644 index 00000000..1aa94a42 --- /dev/null +++ b/4 WEEK/item-service/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/4 WEEK/item-service/gradlew.bat b/4 WEEK/item-service/gradlew.bat new file mode 100644 index 00000000..93e3f59f --- /dev/null +++ b/4 WEEK/item-service/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/4 WEEK/item-service/item-service/.gitignore b/4 WEEK/item-service/item-service/.gitignore new file mode 100644 index 00000000..c2065bc2 --- /dev/null +++ b/4 WEEK/item-service/item-service/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/4 WEEK/item-service/item-service/build.gradle b/4 WEEK/item-service/item-service/build.gradle new file mode 100644 index 00000000..34550a7d --- /dev/null +++ b/4 WEEK/item-service/item-service/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.1.6' + id 'io.spring.dependency-management' version '1.1.4' +} + +group = 'hello' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '17' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +tasks.named('bootBuildImage') { + builder = 'paketobuildpacks/builder-jammy-base:latest' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/4 WEEK/item-service/item-service/gradle/wrapper/gradle-wrapper.jar b/4 WEEK/item-service/item-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..7f93135c Binary files /dev/null and b/4 WEEK/item-service/item-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/4 WEEK/item-service/item-service/gradle/wrapper/gradle-wrapper.properties b/4 WEEK/item-service/item-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3fa8f862 --- /dev/null +++ b/4 WEEK/item-service/item-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/4 WEEK/item-service/item-service/gradlew b/4 WEEK/item-service/item-service/gradlew new file mode 100644 index 00000000..1aa94a42 --- /dev/null +++ b/4 WEEK/item-service/item-service/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/4 WEEK/item-service/item-service/gradlew.bat b/4 WEEK/item-service/item-service/gradlew.bat new file mode 100644 index 00000000..93e3f59f --- /dev/null +++ b/4 WEEK/item-service/item-service/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/4 WEEK/item-service/item-service/settings.gradle b/4 WEEK/item-service/item-service/settings.gradle new file mode 100644 index 00000000..df5bd80b --- /dev/null +++ b/4 WEEK/item-service/item-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'item-service' diff --git a/4 WEEK/item-service/item-service/src/main/java/hello/itemservice/ItemServiceApplication.java b/4 WEEK/item-service/item-service/src/main/java/hello/itemservice/ItemServiceApplication.java new file mode 100644 index 00000000..1311934b --- /dev/null +++ b/4 WEEK/item-service/item-service/src/main/java/hello/itemservice/ItemServiceApplication.java @@ -0,0 +1,13 @@ +package hello.itemservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ItemServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ItemServiceApplication.class, args); + } + +} diff --git a/4 WEEK/item-service/item-service/src/main/resources/application.properties b/4 WEEK/item-service/item-service/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/4 WEEK/item-service/item-service/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/4 WEEK/item-service/item-service/src/test/java/hello/itemservice/ItemServiceApplicationTests.java b/4 WEEK/item-service/item-service/src/test/java/hello/itemservice/ItemServiceApplicationTests.java new file mode 100644 index 00000000..e2ded1be --- /dev/null +++ b/4 WEEK/item-service/item-service/src/test/java/hello/itemservice/ItemServiceApplicationTests.java @@ -0,0 +1,13 @@ +package hello.itemservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ItemServiceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/4 WEEK/item-service/settings.gradle b/4 WEEK/item-service/settings.gradle new file mode 100644 index 00000000..df5bd80b --- /dev/null +++ b/4 WEEK/item-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'item-service' diff --git a/4 WEEK/item-service/src/main/java/hello/itemservice/ItemServiceApplication.java b/4 WEEK/item-service/src/main/java/hello/itemservice/ItemServiceApplication.java new file mode 100644 index 00000000..1311934b --- /dev/null +++ b/4 WEEK/item-service/src/main/java/hello/itemservice/ItemServiceApplication.java @@ -0,0 +1,13 @@ +package hello.itemservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ItemServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ItemServiceApplication.class, args); + } + +} diff --git a/4 WEEK/item-service/src/main/java/hello/itemservice/item/Item.java b/4 WEEK/item-service/src/main/java/hello/itemservice/item/Item.java new file mode 100644 index 00000000..78b4c9a2 --- /dev/null +++ b/4 WEEK/item-service/src/main/java/hello/itemservice/item/Item.java @@ -0,0 +1,19 @@ +package hello.itemservice.item; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Item { + private Long id; + private String name; + private Integer price; + private Integer quantity; + + public Item(String name, Integer price, Integer quantity){ + this.name = name; + this.price = price; + this.quantity = quantity; + } +} diff --git a/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemController.java b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemController.java new file mode 100644 index 00000000..7481267e --- /dev/null +++ b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemController.java @@ -0,0 +1,66 @@ +package hello.itemservice.item; + +import jakarta.annotation.PostConstruct; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +@RequestMapping("/item") +public class ItemController { + + private final ItemRepository itemRepository; + + @Autowired + public ItemController(ItemRepository itemRepository) { + this.itemRepository = itemRepository; + } + + @GetMapping("/itemListForm") + public String getItemListForm(Model model){ + List itemList = itemRepository.findAll(); + model.addAttribute("itemList",itemList); + return "ItemListForm"; + } + + @GetMapping("/{itemId}") + public String getItemDetailForm(@PathVariable Long itemId, Model model){ + Item item = itemRepository.findById(itemId); + model.addAttribute("item",item); + return "ItemDetailForm"; + } + + @GetMapping("/itemSave") + public String getItemSaveForm(){ + return "ItemSaveForm"; + } + + @PostMapping("/itemSave") + public String itemSave(@ModelAttribute Item item){ + itemRepository.save(item); + return "ItemDetailForm"; + } + + @GetMapping("/{itemId}/itemUpdate") + public String getItemUpdateForm(@PathVariable Long itemId, Model model){ + Item updateItem = itemRepository.findById(itemId); + model.addAttribute("item",updateItem); + return "ItemUpdateForm"; + } + + @PostMapping("/{itemId}/itemUpdate") + public String itemUpdate(@PathVariable Long itemId, @ModelAttribute Item item){ + itemRepository.update(itemId, item); + return "redirect:/item/{itemId}"; + } + + @PostConstruct + public void init(){ + itemRepository.save(new Item("testA",1000,10)); + itemRepository.save(new Item("testB",2000,20)); + } +} diff --git a/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemRepository.java b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemRepository.java new file mode 100644 index 00000000..c9901491 --- /dev/null +++ b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemRepository.java @@ -0,0 +1,14 @@ +package hello.itemservice.item; + +import org.springframework.stereotype.Repository; + +import java.util.List; + + +public interface ItemRepository { + Item save(Item item); + Item findById(Long itemId); + void update(Long itemId, Item updatedItem); + List findAll(); + void clearStore(); +} diff --git a/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemService.java b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemService.java new file mode 100644 index 00000000..6f5d5005 --- /dev/null +++ b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemService.java @@ -0,0 +1,10 @@ +package hello.itemservice.item; + +import org.springframework.stereotype.Service; + + +public interface ItemService { + void join(Item item); + void updateItem(Item item, String itemName, double itemPrice, int itemQuantity); + Item findItem(Long itemId); +} diff --git a/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemServiceImpl.java b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemServiceImpl.java new file mode 100644 index 00000000..36aee200 --- /dev/null +++ b/4 WEEK/item-service/src/main/java/hello/itemservice/item/ItemServiceImpl.java @@ -0,0 +1,32 @@ +package hello.itemservice.item; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ItemServiceImpl implements ItemService{ + private final ItemRepository itemRepository; + + @Autowired + public ItemServiceImpl(ItemRepository itemRepository) { + this.itemRepository = itemRepository; + } + + @Override + public void join(Item item) { + itemRepository.save(item); + } + + @Override + public void updateItem(Item item, String itemName, double itemPrice, int itemQuantity) { + item.setName(itemName); + item.setPrice(itemPrice); + item.setQuantity(itemQuantity); + itemRepository.update(item); + } + + @Override + public Item findItem(Long itemId) { + return itemRepository.findById(itemId); + } +} diff --git a/4 WEEK/item-service/src/main/java/hello/itemservice/item/MemoryItemRepository.java b/4 WEEK/item-service/src/main/java/hello/itemservice/item/MemoryItemRepository.java new file mode 100644 index 00000000..3a710bff --- /dev/null +++ b/4 WEEK/item-service/src/main/java/hello/itemservice/item/MemoryItemRepository.java @@ -0,0 +1,45 @@ +package hello.itemservice.item; + +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +public class MemoryItemRepository implements ItemRepository { + private static Map store = new HashMap<>(); + private static long SEQUENCE = 0L; + @Override + public Item save(Item item) { + item.setId(++SEQUENCE); + store.put(item.getId(),item); + return item; + } + + @Override + public Item findById(Long itemId) { + return store.get(itemId); + } + + @Override + public void update(Long itemId, Item updatedItem) { + Item findItem = findById(itemId); + findItem.setName(updatedItem.getName()); + findItem.setPrice(updatedItem.getPrice()); + findItem.setQuantity(updatedItem.getQuantity()); + } + + @Override + public List findAll(){ + return new ArrayList<>(store.values()); + } + + @Override + public void clearStore(){ + store.clear(); + SEQUENCE = 0L; + } + +} diff --git a/4 WEEK/item-service/src/main/resources/application.properties b/4 WEEK/item-service/src/main/resources/application.properties new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/4 WEEK/item-service/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/4 WEEK/item-service/src/main/resources/static/index.html b/4 WEEK/item-service/src/main/resources/static/index.html new file mode 100644 index 00000000..76ee3ab3 --- /dev/null +++ b/4 WEEK/item-service/src/main/resources/static/index.html @@ -0,0 +1,16 @@ + + + + + Title + + + + + \ No newline at end of file diff --git a/4 WEEK/item-service/src/main/resources/templates/ItemDetailForm.html b/4 WEEK/item-service/src/main/resources/templates/ItemDetailForm.html new file mode 100644 index 00000000..3359be49 --- /dev/null +++ b/4 WEEK/item-service/src/main/resources/templates/ItemDetailForm.html @@ -0,0 +1,34 @@ + + + + + 상품 상세 + + + +
+

상품 상세

+
+
+ 상품 ID
+
+ 상품명
+
+ 가격
+
+ 수량
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/4 WEEK/item-service/src/main/resources/templates/ItemListForm.html b/4 WEEK/item-service/src/main/resources/templates/ItemListForm.html new file mode 100644 index 00000000..887cd187 --- /dev/null +++ b/4 WEEK/item-service/src/main/resources/templates/ItemListForm.html @@ -0,0 +1,42 @@ + + + + + 상품 목록 + + + +
+

상품 목록

+
+ +
+ + + + \ No newline at end of file diff --git a/4 WEEK/item-service/src/main/resources/templates/ItemSaveForm.html b/4 WEEK/item-service/src/main/resources/templates/ItemSaveForm.html new file mode 100644 index 00000000..5116207f --- /dev/null +++ b/4 WEEK/item-service/src/main/resources/templates/ItemSaveForm.html @@ -0,0 +1,30 @@ + + + + + 상품 등록 + + + +
+

상품 등록 폼

+
+
+

상품 입력

+ 상품명
+
+ 가격
+
+ 수량
+
+
+ + +
+ + \ No newline at end of file diff --git a/4 WEEK/item-service/src/main/resources/templates/ItemUpdateForm.html b/4 WEEK/item-service/src/main/resources/templates/ItemUpdateForm.html new file mode 100644 index 00000000..13c65d39 --- /dev/null +++ b/4 WEEK/item-service/src/main/resources/templates/ItemUpdateForm.html @@ -0,0 +1,31 @@ + + + + + 상품 수정 + + + +
+

상품 수정 폼

+
+
+ 상품 ID
+
+ 상품명
+
+ 가격
+
+ 수량
+
+
+ + +
+ + \ No newline at end of file diff --git a/4 WEEK/item-service/src/test/java/hello/itemservice/ItemRepositoryTest.java b/4 WEEK/item-service/src/test/java/hello/itemservice/ItemRepositoryTest.java new file mode 100644 index 00000000..dbf9dd01 --- /dev/null +++ b/4 WEEK/item-service/src/test/java/hello/itemservice/ItemRepositoryTest.java @@ -0,0 +1,70 @@ +package hello.itemservice; + +import hello.itemservice.item.Item; +import hello.itemservice.item.ItemRepository; +import hello.itemservice.item.MemoryItemRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ItemRepositoryTest { + private ItemRepository itemRepository = new MemoryItemRepository(); + + @AfterEach + void afterLogic(){ + itemRepository.clearStore(); + } + + @Test + void saveTest(){ + //given + Item item = new Item("itemA",1000,10); + + //when + Item savedItem = itemRepository.save(item); + + //then + Item findItem = itemRepository.findById(item.getId()); + assertThat(findItem).isEqualTo(savedItem); + } + + @Test + void findAllTest(){ + //given + Item item1 = new Item("item1",10000,10); + Item item2 = new Item("item2",2000,20); + + itemRepository.save(item1); + itemRepository.save(item2); + + //when + List itemList = itemRepository.findAll(); + + //then + assertThat(itemList.size()).isEqualTo(2); + assertThat(itemList).contains(item1,item2); + } + + @Test + void updateTest(){ + //given + Item item = new Item("item1",10000,10); + + Item savedItem = itemRepository.save(item); + Long itemId = savedItem.getId(); + + //when + Item updateItem = new Item("item2", 20000, 30); + itemRepository.update(itemId, updateItem); + + Item findItem = itemRepository.findById(itemId); + + //then + assertThat(findItem.getName()).isEqualTo(updateItem.getName()); + assertThat(findItem.getPrice()).isEqualTo(updateItem.getPrice()); + assertThat(findItem.getQuantity()).isEqualTo(updateItem.getQuantity()); + } +} diff --git a/4 WEEK/item-service/src/test/java/hello/itemservice/ItemServiceApplicationTests.java b/4 WEEK/item-service/src/test/java/hello/itemservice/ItemServiceApplicationTests.java new file mode 100644 index 00000000..e2ded1be --- /dev/null +++ b/4 WEEK/item-service/src/test/java/hello/itemservice/ItemServiceApplicationTests.java @@ -0,0 +1,13 @@ +package hello.itemservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ItemServiceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/7 WEEK/7 WEEK MISSION.md b/7 WEEK/7 WEEK MISSION.md index fbd823ff..a14967b0 100644 --- a/7 WEEK/7 WEEK MISSION.md +++ b/7 WEEK/7 WEEK MISSION.md @@ -37,7 +37,187 @@ spring 핵심원리 기본편은 학교에서 대부분 진행한 내용으로 read me 는 필요 시 다시 꺼내서 볼 수 있는 중요자료가 될 것 입니다. --- +

스프링 핵심 원리 기본편 8-9강 요약

+
+

빈 생명주기 콜백 시작


+데이터베이스 커넥션 풀이나, 네트워크 소켓처럼 애플리케이션 시작 시점에 필요한 연결을 미리 해두고, 애플리케이션종료 시점에 연결을 모두 종료하는 작업을 진행하려면, 객체의 초기화와 종료 작업이 필요.
+
+객체를 생성하는 단계에는 url이 없고, 객체를 생성한 다음에 외부에서 수정자 주입을 통해서 setUrl()이 호출되어야 url이 존재하게됨.
+
+

스프링 빈 라이프사이클


+객체 생성 -> 의존관계 주입
+스프링은 의존관계 주입이 완려되면 스프링 빈에게 콜백 메서드를 통해서 초기화 시점을 알려주는 다양한 기능을 제공하고 스프링 컨테이너가 종료되기 직전에 소멸 콜백을 줌.
+
+

스프링 빈의 이벤트 라이프사이클


+스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료
+- 초기화 콜백: 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출
+- 소멸전 콜백: 빈이 소멸되기 직전에 호출
+
+! 객체의 생성과 초기화를 분리
+: 생성자 안에서 초기화 작업을 함께 하는 것 보다 분리하여 명확하게 나누는 것이 유지보수 관점에서 좋음.
+
+! 싱글톤 빈들은 스프링 컨테이너가 종료될 때 함께 종료되기 때문에 스프링 컨테이너가 종료되기 직전에 소멸전 콜백이 일어남.
+
+

스프링의 빈 생명주기 콜백 지원


+1. 인터페이스
+- InitializingBean은 afterPropertiesset() 메서드로 초기화 지원
+- DisposableBean은 destroy() 메서드로 소멸 지원
+- 초기화, 소멸 인터페이스 단점:
+ 스프링 전용 인터페이스이기 때문에 코드가 스프링 전용 인터페이스에 의존,
+ 초기화, 소멸 메서드의 이름 변경 불가,
+ 코드를 고칠 수 없는 외부 라이브러리에 적용할 수 없음
+
+2. 설정 정보에 초기화 메서드, 종료 메서드 지정
+- 설정 정보에 @Bean(initMethod=“init”, destroyMethod=“close”)와 같이 초기화, 소멸 메서드를 지정할 수 있음.
+- 설정 정보 사용 특징:
+ 메서드 이름을 자유롭게 지정 가능,
+ 스프링 빈이 스프링 코드에 의존 하지않음,
+ 외부 라이브러리에도 초기화, 종료 메서드를 적용 가능
+- 종료 메서드 추론
+ @Bean의 destroyMethod는 기본값이 inferred로 등록되어있음,
+ inferred는 close, shutdown라는 이름의 메서드를 자동으로 호출,
+ 직접 스프링 빈으로 등록하면 종료 메서드는 따로 적어주지 않아도 잘 동작함,
+ inferred 기능을 사용하기 싫으면 destoryMedthod=“”로 빈 공백을 지정해주면 됨
+
+3. @PostConstruct, @PreDestroy 어노테이션 지원
+- 특징:
+ 매우 편리함, 최신 스프링에서 가장 권장하는 방법,
+ 스프링에 종속적인 기술이 아니라 스프링이 아닌 다른 컨테이너에서도 동작,
+ 컴포턴트 스캔과 잘 어울림,
+- 단점:
+ 외부 라이브러리에 적용하지 못함
+
+정리
+@PostConstruct, @PreDestroy 어노테이션을 주로 사용하되, 코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야 된다면 @Bean의 intiMethod, destroyMethod를 사용하자.
+
+

빈 스코프


+빈이 존재할 수 있는 범위
+
+

스프링의 스코프 지원


+1. 싱글톤: 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
+- 싱글톤 스코프의 빈을 조회하면 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈을 반환.
+- 싱글톤 빈 요청:
+ 싱글톤 스코프의 빈을 스프링 컨테이너에 요청
+ -> 스프링 컨테이너는 본인이 관리하는 스프링 빈을 반환
+ -> 이후에 스프링 컨테이너에 같은 요청이 와도 같은 객체 인스턴스의 스피링 빈을 반환
+- 싱글톤 빈은 스프링 컨테이너 생성 시점에 초기화 메서드가 실행됨.
+- 싱글톤 빈은 스프링 컨테이너가 관리하기 때문에 컨테이너가 종료될 때 빈의 종료 메서드가 실행됨.
+
+2. 프로토타입: 스프링 컨테이너가 프로토타입 빈의 생성과 의존관계 주입까지만 관여하는 매우 짧은 범위의 스코프
+- 프로토타입 스코프를 스프링 컨테이너에 조회하면 스프링 컨테이너는 항상 새로운 인스턴스를 생성하여 반환
+- 프로토타입 빈 요청:
+ 프로토타입 스코프의 빈을 스프링 컨테이너에 요청:
+ -> 스프링 컨테이너는 이 시점에 프로토타입 빈을 생성하고, 필요한 의존관계를 주입
+ -> 생성한 프로토타입 빈을 클라이언트에 반환
+ -> 이후에 스프링 컨테이너에 같은 요청이 오면 항상 새로운 프로토타입 빈을 생성하여 반환
+- 핵심:
+ 스프링 컨테이너는 프로토타입 빈을 생성하고, 의존관계 주입, 초기화까지만 처리,
+ 생성된 프로토타입 빈을 관리하지 않음,
+ 따라서, @PreDestory 같은 종료 메서드가 호출되지 않음
+- 프로토타입 스코프의 빈은 스프링 컨테이너에서 빈을 조회할 때 생성되고, 초기화 메서드도 실행됨.
+- 프로토타입 빈을 2번 조회하면 완전히 다른 스프링 빈이 생성되고, 초기화도 2번 실행됨.
+- 싱글톤 빈과 함께 사용시 문제점:
+ 싱글톤 빈과 함께 사용할 때는 의도한 대로 잘 동작하지 않으므로 주의해야 함.
+
+3. 웹 관련 스코프
+- request: 웹 요청이 들어오고 나갈 때까지 유지되는 스코프
+- session: 웹 세션이 생성되고 종료될 때까지 유지되는 스코프
+- application: 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프
+

빈 스코프 등록 예시


+- 컴포넌트 스캔 자동 등록
+@Scope(“prototype”)
+@Component
+- 수동 등록
+@Scope(“prototype”)
+@Bean
+
+

싱글톤에서 프로토타입 빈 사용


+싱글톤 빈이 내부에 가지고 있는 프로토타입 빈은 이미 과거에 주입이 끝난 빈이라, 주입 시점에 스프링 컨테이너에 요청해서 프로토타입 빈이 새로 생성이 된 것이지, 사용할 때마다 새로 생성되는 것은 아님.
+- 문제점:
+ 싱글톤 빈은 생성 시점에만 의존관계 주입을 받기 때문에, 프로토타입 빈이 새로 생성되기는 하지만, 싱글톤 빈과 함계 계속 유지되는 것이 문제
+
+! 여러 빈에서 같은 프로토타입 빈을 주입 받으면, 주입 받는 시점에 각각 새로운 프로토타입 빈이 생성됨.
+
+

프로토타입 스코프, 싱글톤 빈과 함께 사용시 Provider로 문제 해결


+1. 스프링 컨테이너에 요청
+- 싱글톤 빈이 프로토타입을 사용할 때 마다 스프링 컨테이너에 새로 요청하는 것
+- 핵심 코드
+@Autowired
+private ApplicationContext ac;
+public int logic() {
+ PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
+ prototypeBean.addCount();
+ int count = prototypeBean.getCount();
+ return count;
+}
+- 단점:
+ 스프링의 애플리케이션 컨텍스트 전체를 주입받게 되면, 스프링 컨테이너에 종속적인 코드가 되고, 단위 테스트도 어려워짐.
+
+2. ObjectFactory, ObjectProvider
+ObjectProvider는 지정한 빈을 컨테이너에서 대신 찾아주는 DL 서비스를 제공함.
+- ObjectProvider의 getObject()를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아 반환함.(DL)
+- 스프링이 제공하는 기능을 사용하지만, 기능이 단순하므로 단위테스트를 만들거나 mock 코드를 만들기가 쉬워짐.
+- 특징:
+ ObjectFactory: 기능이 단순, 별도의 라이브러리 필요 없음, 스프링에 의존
+ ObjectProvider: ObjectFactory 상속, 옵션, 스트림 처리등 편의 기능이 많고, 별도의 라이브러리 필요없음, 스프링에 의존
+
+3. JSR-330 Provider
+javax.inject.Provider라는 JSR-330 자바 표준을 사용
+- 이 방법을 사용하려면 gradle에 라이브러리를 추가해야함
+ 스프링부트 3.0 미만: javax.inject:javax.inject:
+ 스프링부터 3.0 이상: jakarta.inject:jakarta.inject-api:2.0.1
+- provider의 get()을 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환.(DL)
+- 특징:
+ 기능이 단순하므로 단위테스트를 만들거나, mock 코드를 만들기 훨씬 쉬워짐
+ get() 메서드 하나로 기능이 매우 단순함
+ 별도의 라이브러리가 필요
+ 자바 표준이므로 스프링이 아닌 다른 컨테이너에서도 사용 가능
+
+! @Lookup 어노테이션을 사용하는 방법도 있음.
+
+

정리


+매번 사용할 때마다 의존관계 주입이 완료된 새로운 객체가 필요하면 프로토타입 빈 사용.
+ObjectProvider, JSR330 Provider등은 프로토타입 뿐만 아니라 DL이 필요한 경우는 언제든지 사용 가능.
+
+

웹 스코프


+- 특징:
+ 웹 환경에서만 동작
+ 프로토타입과 다르게 스프링이 해당 스코프의 종료 시점까지 관리하여 종료 메서드가 호출됨
+- request: HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리됨
+ 동시에 여러 HTTP 요청이 오면 정확히 어떤 요청이 남긴 로그인지 구분하기 힘들 때 사용하기 좋음
+
+- session: HTTP Session과 동일한 생명주기를 가지는 스코프
+ +- application: 서블릿 컨텍스트와 동일한 생명주기를 가지는 스코프
+ +- websocket: 웹 소켓과 동일한 생명주기를 가지는 스코프
+ +스프링 애플리케이션을 실행하는 시점에 싱글톤 빈은 생성해서 주입이 가능하지만, reqeust 스코프 빈은 아직 생성되지 않아 오류가 발생.
+1. Provider
+- ObjectProvider.getObject()를 호출하는 시점까지 request 스코프 빈의 생성을 지연할 수 있음.
+- ObjectProvider.getObject()를 호출하는 시점에는 HTTP 요청이 진행중이므로 request 스코프 빈의 생성이 정상 처리됨.
+- Controller, Service에서 각각 한번씩 따로 호출해도 같은 HTTP 요청이면 같은 스프링 빈이 반환됨.
+
+2. Proxy
+- 핵심: proxyMode=ScopedProxyMode.TARGET_CLASS
+ 적용 대상이 인터페이스가 아니면 TARGET_CLASS,
+ 적용 대상이 인터페이스면 INTERFACES
+- 가짜 프록시 클래스를 만들어두고 HTTP request와 상관없이 가짜 프록시 클래스를 다른 빈에 미리 주입해 둘 수 있음.
+- 동작 원리:
+ CGLIB라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입.
+ 이 가짜 프록시 객체는 실제 요청이 오면 그때 내부에서 실제 빈을 요청하는 위임 로직이 들어있음.
+ 가짜 프록시 객체는 실제 request scope와는 관계가 없음.
+ 그냥 가짜이고, 내부에 단순한 위임 로직만 있고, 싱글톤처럼 동작.
+- 특징:
+ 진짜 객체 조회를 꼭 필요한 시점까지 지연처리 함.
+ 어노테이션 설정 변경만으로 원본 객체를 프록시 객체로 대체할 수 있음.
+ 웹 스코프가 아니어도 프록시 사용 가능
+- 주의점:
+ 싱글톤과 비슷하지만 다르게 동작하기 때문에 주의해서 사용해야함.
+ 꼭 필요한 곳에만 최소화하여 사용.
+ 무분별하게 사용하면 유지보수하기 어려워짐.
+
## Commit Message ROLE Header, Body, Footer는 빈 행으로 구분한다
...
diff --git a/8 WEEK/8 WEEK MISSION.md b/8 WEEK/8 WEEK MISSION.md index 2a9fc2ac..8461b5d9 100644 --- a/8 WEEK/8 WEEK MISSION.md +++ b/8 WEEK/8 WEEK MISSION.md @@ -34,6 +34,99 @@ MVC-1 1장 ~ 4장입니다.
read me 는 필요 시 다시 꺼내서 볼 수 있는 중요자료가 될 것 입니다. --- +

스프링 MVC 1-4강 요약


+
+

MVC 패턴

+Model View Controller: JSP로 처리하던 것을 Controller와 View의 영역으로 역할을 나눈 것.
+-모델: 뷰에 출력할 데이터를 담아둠
+-컨트롤러: HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직을 실행, 뷰에 전달할 결과 데이터를 조회해서 모델에 담아둠
+-뷰: 모델에 담겨있는 데이터를 사용해서 화면을 출력
+
+!컨트롤러에 비즈니스 로직을 두면 너무 많은 역할을 담당하게 되어, 서비스라는 계층을 별도로 만들어 처리함. 컨트롤러는 비즈니스 로직이 있는 서비스를 호출하는 역할을 담당.
+
+

MVC 패턴의 한계


+-MVC 컨트롤러의 단점:
+ 포워드 중복: View로 이동하는 코드가 항상 중복 호출되어야함
+ ViewPath의 중복, jsp가 아닌 thymeleaf같은 다른 뷰로 변경하면 전체 코드를 다 변경해야함
+ 사용하지 않는 코드: HttpServletRequest, HttpServletResponse등을 사용할 때도 있고, 하지 않을 때도 있음
+ 공통 처리의 어려움: 기능이 복잡해질수록 컨트롤러에서 공통으로 처리해야하는 부분이 증가, 실수로 호출하지 않으면 문제가 됨
+
+

프론트 컨트롤러


+프론트 컨트롤러 서블릿 하나로 클라이언트의 요청을 받아 맞는 컨트롤러를 찾아서 호출
+-특징: 공통 처리 기능, 프론트 컨트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 됨
+
+

프론트 컨트롤러 도입 V-1


+urlPatterns=“/front-controller/v1/*” 로 지정하여 /front-controller/v1을 포함한 하위 모든 요청이 이 서블릿에서 받아들이도록 함
+-주요 코드:
+urlPatterns 지정
+@WebServlet(name = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*")
+url 매핑
+public FrontControllerServletV1() {
+ controllerMap.put("/front-controller/v1/members/new-form", new MemberFormControllerV1());
+ controllerMap.put("/front-controller/v1/members/save", new MemberSaveControllerV1());
+ controllerMap.put("/front-controller/v1/members", new MemberListControllerV1());
+ }
+ +

프론트 컨트롤러 View 분리 V-2


+모든 컨트롤러에 뷰로 이동하는 부분이 중복됨
+-주요 코드:
+객체를 생성하여 뷰 이름을 넣고 반환
+return new MyView("/WEB-INF/views/new-form.jsp");
+return new MyView("/WEB-INF/views/save-result.jsp");
+return new MyView("/WEB-INF/views/members.jsp");
+
+

프론트 컨트롤러 Model 추가 V-3


+-서블릿 종속성 제거:
+ 컨트롤러 입장에서 HttpServletRequest, HttpServletResponse는 꼭 필요하지 않음
+ 요청 파라미터 정보는 Map으로 대신 넘기도록하면 컨트롤러가 서블릿 기술을 몰라도 동작 가능함
+-뷰 이름 중복 제거:
+ 컨트롤러는 뷰의 논리 이름을 반환하고, 실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 함
+-뷰 리졸버:
+ 컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경시킴, 실제 물리 경로가 있는 객체를 반환
+-주요 코드:
+뷰의 논리적인 이름 지정
+@Override
+ public ModelView process(Map paramMap) {
+ return new ModelView("new-form");
+ }
+뷰의 실제 물리 경로가 있는 객체 반환
+MyView view = viewResolver(viewName);
+private MyView viewResolver(String viewName) {
+ return new MyView("/WEB-INF/views/" + viewName + ".jsp");
+ }
+
+ +

프론트 컨트롤러 단순하고 실용적인 V-4


+ModelView 객체를 생성하고 반환하는 부분이 번거로우므로, 컨트롤러가 ModelView대신 ViewName만 반환하도록 함.
+모델이 파라미터로 전달되기 때문에, 모델을 직접 생성하지 않아도 됨.
+-주요 코드:
+뷰의 논리 이름 반환
+@Override
+ public String process(Map paramMap, Map model) {
+ return "new-form";
+ }
+
+

프론트 컨트롤러 유연한 컨트롤러 V-5


+컨트롤러V3과 컨트롤러V4는 완전히 다른 인터페이스이기 때문에 호환이 불가능.
+어댑터 패턴을 사용하여 프론트 컨트롤러가 다양한 방식의 컨트롤러를 처리할 수 있도록 변경.
+-핸들러 어댑터:
+ 어댑터 역할을 해주어 다양한 종류의 컨트롤러를 호출
+-핸들러:
+ 컨트롤러를 더 넓은 범위의 핸들러로 변경
+-주요 코드:
+ 어댑터 인터페이스
+public interface MyHandlerAdapter {
+ boolean supports(Object handler);
+ ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException;
+}
+어댑터 구현
+@Override
+ public boolean supports(Object handler) {
+ return (handler instanceof ControllerV4);
+ }
+ + + ## Commit Message ROLE Header, Body, Footer는 빈 행으로 구분한다
diff --git a/9 WEEK/9 WEEK MISSION.md b/9 WEEK/9 WEEK MISSION.md index 81f85e9d..ebdb0087 100644 --- a/9 WEEK/9 WEEK MISSION.md +++ b/9 WEEK/9 WEEK MISSION.md @@ -35,6 +35,166 @@ Server 개발자의 기본 소양인 Spring MVC 부분 입니다.
read me 는 필요 시 다시 꺼내서 볼 수 있는 중요자료가 될 것 입니다. --- +

스프링 MVC 5-7강 요약

+
+

스프링 MVC 전체 구조

+HTTP 요청
+-> 1. 핸들러 조회
+-> 핸들러를 처리할 수 있는 핸들러 어댑터 조회
+-> 핸들러 어댑터 실행: handle(handler)
+-> 핸들러 호출
+-> MovdelView 반환
+-> viewResolver 호출
+-> View 반환
+-> 뷰 렌더링: render(model)
+-> HTML 응답
+
+

DispatcherServlet 구조

+스프링 MVC의 프론트 컨트롤러가 디스패처 서블릿임.
+-요청의 흐름:
+ 서블릿이 호출되면
+ -> HttpServlet.service() 호출 -> DispatcherServlet의 부모인 FrameworkServlet에서 service()를 오버라이드 해두어 FramworkServlet.service()로 여러 메서드가 호출됨 -> DispatcherServlet.doDispatch() 호출
+
+

HttpRequestHandler

+서블릿과 가장 유사한 형태의 핸들러.
+-동작 방식:
+핸들러 매핑으로 핸들러 조회 -> 핸들러 어댑터 조회 -> 핸들러 어댑터 실행
+
+

InternalResourceViewResolver

+-동작 방식:
+핸들러 어댑터 호출 -> ViewResolver 호출 -> InternalResourceViewResolver로 InternalResourceView 반환 -> InternalResourceView로 forward() 호출 -> view.render() 호출
+
+

@RequestMapping

+요청 정보를 매핑, 해당 URL이 호출되면 그 메서드가 호출됨.
+대부분의 속성을 배열로 제공하여 다중 설정이 가능.
+-메서드 구분
+@RequestMapping(value=“”, method = RequestMethod.GET) -> @GetMapping
+@RequestMapping(value=“”, method = RequestMethod.POST) -> @PostMapping
+-그 외: Put, Delete, Patch
+
+

@Controller

+스프링이 자동으로 스프링 빈으로 등록해줌.
+
+

로그

+-로그 라이브러리:
+SLF4J(인터페이스), Logback(구현체)
+-로그 선언:
+private Logger log = LoggerFactory.getLogger(getClass());
+private static final Logger log = LoggerFactory.getLogger(Xxx.class);
+@Slf4j(롬복 사용)
+-로그 호출:
+log.info(“”)
+-Level:
+TRACE >DEBUG > INFO > WARN > ERROR
+개발 서버는 debug, 운영 서버는 info로 출력.
+-장점:
+스레드 정보와 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정 가능.
+로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영 서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절 가능.
+파일이나 네트워크 등 로그를 별도의 위치에 남길 수 있음
+System.out 보다 성능이 좋음
+
+

@RestController

+반환 값으로 뷰를 찾는 것이 아닌, HTTP 메시지 바디에 바로 입력.
+
+

@PathVariable

+변수명이 같으면 생략 가능.
+
+

@RequestHeader(“”)

+특정 HTTP 헤더를 조회.
+
+

@CookieValue(value=“”, required=)

+특정 쿠키를 조회.
+
+

요청 파라미터

+-GET - 쿼리 파라미터
+메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해 전달.
+/request-param?username=hello&age=20
+
+-POST – HTML Form
+메시지 바디에 쿼리 파라미터 형식으로 전달
+content-type: application/x-www-form-urlencoded
+username=hello&age=20
+
+-HTTP message body에 데이터를 직접 담아서 요청
+데이터 형식은 주로 JSON, HTTP API에서 주로 사용
+
+

@RequestParam

+파라미터 이름으로 바인딩.
+HTTP 파라미터 이름이 변수 이름과 같다면 생략 가능.
+파라미터 이름만 있고 값이 없는 경우에는 빈 문자로 통과.
+
+

@ResponseBody

+View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력.
+-동작 원리:
+HTTP의 body에 문자 내용을 직접 반환 -> viewResolver 대신 HttpMessageConverter 동작
+
+

@RequestBody

+HTTP 메시지 바디 정보를 조회.
+생략 불가능. (생략하면 @ModelAttribute가 됨)
+
+

@RequestParam Map<>, MultiValueMap<>

+파라미터를 Map, MultiValueMap으로 조회 가능.
+
+

@Data

+@Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor를 자동으로 적용
+
+

@ModelAttribute

+HTTP 요청 파라미터나 multipart/form-data 형태의 파라미터를 받아 객체로 사용.
+생략 가능하여 @RequestParam과 헷갈릴 수 있음.
+-규칙:
+String, int, Integer -> @RequestParam
+나머지 -> @ModelAttribute
+
+

InputStream

+HTTP 요청 메시지 바디의 내용을 직접 조회.
+
+

OutputStream

+HTTP응답 메시지의 바디에 직접 결과 출력.
+
+

HTTPEntity

+메시지 바디 정보를 직접 조회, 반환 가능.
+헤더 정보 포함 가능.
+요청 파라미터 조회x, view 조회x.
+
+

RequestEntity

+HttpMethod, url 정보 추가, 요청에서 사용.
+
+

요청 매핑 핸들러 어댑터

+-RequestMappingHandlerAdapter 동작 방식:
+컨트롤러의 파라미터, 어노테이션 정보를 기반으로 전달 데이터 생성 -> 해당 컨트롤러 호출 –> 컨트롤러의 반환 값을 변환
+
+

HTTP 메시지 컨버터

+컨트롤러가 필요로 하는 파라미터의 값에 사용됨.
+-요청:
+ArgumentResolver 가 HTTP 메시지 컨버터를 사용하여 필요한 객체 생성 -> @RequestBody와 HttpEntity 처리
+-응답:
+ReturnValueHandler 가 HTTP 메시지 컨버터를 호출하여 응답 결과 생성 -> @ResponseBody와 HttpEntity 처리
+
+

단위 테스트 – JUnit

+-특징:
+assert 메서드로 테스트 케이스의 수행 결과를 판별
+@Test 메서드가 호출할 때마다 새로운 인스턴스를 생성하여 독립적인 테스트가 가능
+-어노테이션
+@Test: @Test가 선언된 메서드는 테스트를 수행
+@Before: @Test 메서드가 실행되기 전에 해당 메서드가 반드시 실행
+@After: @Test 메서드가 실행된 후 해당 메서드가 실행
+-given/ when/ then 패턴
+준비/ 실행/ 검증.
+given: 테스트에 사용하는 변수, 입력값 등을 정의함
+when: 실제로 동작하는 테스트를 실행함
+then: 예상한 값과 실제 실행을 통해 나온 값을 검증함
+
+

Thymeleaf

+th:xxx 가 붙은 부분은 서버사이드에서 렌더링 되고, 기존 것을 대체.
+th:xxx 이 없으면 기존 html의 xxx속성이 그대로 사용됨.
+-선언:
+
+-표현식:
+th:href=“@{/xxx/xxxxx.xxx.xx}”
+th:onclick=“|location.href=’@{/xxx/xxx/xx}‘|”
+th:each=“item : ${items}”
+th:value=“${item.id}”
+
## Commit Message ROLE Header, Body, Footer는 빈 행으로 구분한다