[스프링 입문] 스프링 예제 프로젝트 PetClinic 1

최진민·2021년 1월 13일
0

스프링 입문

목록 보기
1/4
post-thumbnail

필요 지식
1. 자바 프로그래밍
2. Intellij & eclipse
3. Build tool, Gradle & Maven
4. Git

프로젝트 설정

  • https://github.com/spring-projects/spring-petclinic 에서 git clone(https://github.com/spring-projects/spring-petclinic.git) 복사 후 IntelliJ VCS에서 clone 받기.

  • PetClinc 프로젝트 빌드

    • Terminal을 통해 ./mvnw package 입력
      • 참고 1. ./mvnw package가 되지 않을때, Terminal 설정이 cmd.exe로 되어있는 경우이다. https://medium.com/@violetboralee/intellij-idea와-git-bash-연동하기-63e8216aa7de 링크를 참고하여 Terminal 설정을 sh.exe로 변경.
      • 참고 2. jdk는 8 or 11 권장.
      • 참고 3. "[ERROR]The forked VM terminated without properly saying goodbye. VM crash or System.exit called?" -> 에러가 뜨면 의존성에 아래 추가.
       <build>
        <plugin>
         <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
           <version>2.22.0</version>
            <configuration>
             <skipTests>
              true
             </skipTests>
            </configuration>
        </plugin>
       </build>
      • 성공시, 별다른 [ERROR] 없이 [INFO] BUILD SUCCESS 가 뜬다.
  • PetClinic 프로젝트 실행

    • jar : Java Application aRchive.
    • Terminal 명령어 입력. java -jar target/spring-petclinic-2.4.0.BUILD-SNAPSHOT.jar
    • 주소 창에 http://localhost:8080/을 입력 해보자.
    • 여러 정보를 입력해보자.
  • PetClinic Application 종료 & 실행 방법

    • 종료 : Terminal 에서 Ctrl + C
    • 재실행 : Java 메인 메소드에서 실행
    • 주의할 점!
      ./mvnw package
      java -jar target/*.jar 필요

프로젝트 살펴보기

  • 프로젝트 구조

    • 직접 설정하지 않아도 자동으로 Spring 기반의 Web App이 돌아가게 한다.
  • 프로젝트 분석 - 로그(디버깅으로도 살펴보자)

    • 웹 상에서 요청을 했을 때 요청 사항을 보고 싶다면 손 좀 봐야한다!

    • 현재는 INFO 단계, Debug 단계로 변경.

    • src\main\resources\application.properties 에서

      logging.level.org.springframework=INFO
      logging.level.org.springframework.web=DEBUG # 주석 해제
      # logging.level.org.springframework.context.annotation=TRACE
      • Application 재실행. Ctrl + Shift + F10
        - ERROR Web server failed to start. Port 8080 was already in use. 와 같은 오류가 발생했을 때 해결법은 https://dundung.tistory.com/148를 참고하자.
    • 웹 페이지의 Find Owners 탭으로 이동하여 새로고침을 해보자.

    • 실행중인 Log에서, 다음과 같은 문구를 발견할 수 있다.

      2021-01-13 20:56:13.617 DEBUG 3824 --- [nio-8080-exec-5] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.samples.petclinic.owner.**OwnerController**#**initCreationForm**(Map)

    • OwnerController(Class)을 찾고 initCreationForm(Method)가 호출됨을 알 수 있다.

      private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM =  "owners/createOrUpdateOwnerForm";
      
      @GetMapping("/owners/new")
      	public String initCreationForm(Map<String, Object> model) {
      		 	Owner owner = new Owner();
      		model.put("owner", owner);
      			return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; // 주석
      		 }
    • // 주석 → 반환문의 위치는 main\resources\templates\owners\createOrUpdateOwnerForm.html이다. 이는 웹페이지의 form을 의미한다.
      (간략하게 흐름 타보기)


프로젝트 과제

  • Lastname이 아닌 FirstName으로 검색하기

    • \resources\templates\owners\findOwners.html

      <form th:object="${owner}" th:action="@{/owners}" method="get"
          class="form-horizontal" id="search-owner-form">
          <div class="form-group">
            <div class="control-group" id="lastNameGroup">
              <label class="col-sm-2 control-label">First name </label> 
              <div class="col-sm-10">
                <input class="form-control" th:field="*{firstName}" size="30"
                  maxlength="80" /> <span class="help-inline"><div
                    th:if="${#fields.hasAnyErrors()}">
                    <p th:each="err : ${#fields.allErrors()}" th:text="${err}">Error</p>
                  </div></span>
              </div>
            </div>
          </div>
          <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
              <button type="submit" class="btn btn-default">Find
                Owner</button>
            </div>
          </div>
      
        </form>
    • \owner\OwnerController

      public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
      
      		// allow parameterless GET request for /owners to return all records
      		
      		if (owner.getFirstName() == null){
      			owner.setFirstName("");
      		}
      
      		// find owners by first name
      		Collection<Owner> results = this.owners.findByFirstName(owner.getFirstName());
      		if (results.isEmpty()) {
      			// no owners found
      			result.rejectValue("firstName", "notFound", "not found");
      			return "owners/findOwners";
      		}
      		else if (results.size() == 1) {
      			// 1 owner found
      			owner = results.iterator().next();
      			return "redirect:/owners/" + owner.getId();
      		}
      		else {
      			// multiple owners found
      			model.put("selections", results);
      			return "owners/ownersList";
      		}
      	}
    • \owner\OwnerRepository

      @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.firstName LIKE :firstName%")
      @Transactional(readOnly = true)
      Collection<Owner> findByFirstName(@Param("firstName") String firstName);
  • 키워드로 검색하기. ex) Maria를 "aria"로 검색 가능하게 하기.

    • \owner\OwnerRepository

      @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.firstName LIKE %:firstName%")
  • Owner에 age 추가

    • \owner\Owner

      @Column(name = "age")
      @NotEmpty
      private Integer age;
      
      public Integer getAge() { return this.age; }
      
      public void setAge(Integer age){ this.age = age;	}
    • \resources\db\hsqldb\schema.sql

      CREATE TABLE owners (
        id         INTEGER IDENTITY PRIMARY KEY,
        first_name VARCHAR(30),
        last_name  VARCHAR_IGNORECASE(30),
        address    VARCHAR(255),
        city       VARCHAR(80),
        telephone  VARCHAR(20),
        age        INTEGER #추가
      );
    • \resources\db\hsqldb\data.sql

      INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023', 20);
    • \resources\templates\owners\createOrUpdateOwnerFrom.html

      <div>
      <input
              th:replace="~{fragments/inputField :: input ('Age', 'age', 'text')}" />
      </div>
    • \resources\templates\owners\ownerList.html

      <thead>
      	<tr>
      		<th style="width: 100px">Age</th>
      	</tr>
      </thead>
      
      <tbody>
      	<tr th:each="owner : ${selections}">
      		<td th:text="${owner.age}"/>
      	</tr>
      </tbody>
    • \resources\templates\owners\ownerDetails.html

      <tr>
              <th>Telephone</th>
              <td th:text="*{telephone}"></td>
            </tr>
            <tr>
              <th>Age</th>
              <td th:text="*{age}"></td>
            </tr>
    • 실행시(Ctrl + F9) 오류가 있다면, \resources\application.properties를 살펴보자.

      database=h2 를
      database=hsqldb 로 변경하자
profile
열심히 해보자9999

1개의 댓글

comment-user-thumbnail
2021년 3월 13일

글 잘 읽었습니다! :) 저도 같은 예제를 실행하다가 여쭤 볼게 있어서요!
똑같이 깃헙에서 클론받아서 실행했는데, configuration이 잡히지가 않아서요! 그래서 main 메소드로 애플리케이션이 실행이 안되더라구요..
혹시 인텔리제이 커뮤니티버전을 사용중인데 이게 이유가 될까요..?

답글 달기

관련 채용 정보