CRUD

  • Create (INSERT)
  • Read (SELECT)
  • Update (UPDATE)
  • Delete (DELETE)

Read 구현

필요한 것

  • DB table에서 원하는 내용을 꺼내올 것
  • list 화면에 내용들을 list로 보여줌
  • list들 중 하나를 클릭하면 read화면이 떠서 볼 수 있게

 

❗ C구현에서 했던 filter와 service, repository들을 그대로 활용할 예정 ❗

먼저 list화면을 구현

<!DOCTYPE HTML>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<head>
  <th:block th:replace="fragments/head :: head"></th:block>
  <link rel="stylesheet" th:href="@{/static/assets/css/project-list.css}" type="text/css"/>
  <style>
    h2, p {
      font-weight: bold;
    }
    a {
      text-decoration: none;
      color: #777777;
    }
  </style>
</head>

<body class="is-preload">
<div id="wrapper">
  <th:block th:replace="fragments/top :: top"></th:block>
  <div id="main">
    <article id="work" class="panel">
      <header>
        <h2>Project</h2>
      </header>
      <p>
        A field of interest :
        <span style="font-weight: lighter">Cloud(AWS, OpenStack), WEB(Spring), DevOps</span>
      </p>

      <table class="type09">
        <thead>
        <tr>
          <th scope="col">No.</th>
          <th scope="col">Progress Date</th>
          <th scope="col">Project Title</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="p: ${projectList}">
          <td scope="row" style="width: 50px"><a th:text="${p.id}" th:href="|@{/project/read}/${p.id}|"></a> </td>
          <td><a th:text="${p.date}" th:href="|@{/project/read}/${p.id}|"></a> </td>
          <td><a th:text="${p.title}" th:href="|@{/project/read}/${p.id}|"></a> </td>
        </tr>
        </tbody>
      </table>
      <a class="addButton" th:text="|ADD|" th:href="|@{/project/edit}|"></a>
    </article>
  </div>
</div>
<th:block th:replace="fragments/footer :: footer"></th:block>
<th:block th:replace="fragments/common-script :: common-script"/>
</body>
</html>

 

읽을 read화면도 구현

<!DOCTYPE HTML>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<head>
  <th:block th:replace="fragments/head :: head"></th:block>
  <link rel="stylesheet" th:href="@{/static/assets/css/project-read.css}" type="text/css"/>
  <style>
    h2 {
      font-weight: bold;
    }
  </style>
</head>

<body class="is-preload">
<div id="wrapper">

  <th:block th:replace="fragments/top :: top"></th:block>
  <div id="main">
    <article id="work" class="panel" th:object="${project}">
      <h2>Project</h2>
      <div class="mb-3">
        <h4 class="title" th:text="*{title}"></h4>
      </div>
      <div class="mb-3">
        <h5 class="date" th:text="*{date}"></h5>
      </div>
      <hr class="one">
      <div class="mb-3">
        <h5 class="purpose" th:text="*{purpose}"></h5>
      </div>
      <hr class="two">
      <div class="mb-3">
        <h5 class="technology" th:text="*{technology}"></h5>
      </div>
      <hr class="two">
      <div class="mb-3">
        <h5 class="address" th:text="*{address}"></h5>
      </div>

    </article>
  </div>
</div>
<th:block th:replace="fragments/footer :: footer"></th:block>
<th:block th:replace="fragments/common-script :: common-script"/>
</body>
</html>

 

이 화면들을 띄워줄 controller 구현

@Controller
@RequiredArgsConstructor
@RequestMapping("/project")
public class ProjectController {

 @NonNull
  private final ProjectService projectService;

  @GetMapping("")
  public String list(Model model, Pageable pageable, ProjectFilter filter) {

    model.addAttribute("projectList", projectService.findAllByFilter(pageable, filter));
    model.addAttribute("filter", filter);
    return "project/list";
  }
  
   @GetMapping("/read/{id}")
  public String read(@PathVariable Integer id, Model model) {

    Project project = projectService.findById(id).orElseThrow(DataNotFoundException::new);
    model.addAttribute("project",project);

    return "project/read";
  }
}

여기까지 구현하면 CR구현이 완성되었다!

list 화면
read 화면

 

❗ 코드 관련 문법이나 필요한 내용들은 따로 정리할 예정이며 UD는 천천히 구현해볼 예정이다! ❗

'Web > Spring' 카테고리의 다른 글

[설정] 자동망치 기능  (0) 2021.08.06
[설정] application.properties  (0) 2021.08.04
[CRUD] C구현  (0) 2021.08.02
[JPA] 데이터베이스 생성 또는 초기화  (0) 2021.08.02
[ERROR] Pageable import  (0) 2021.08.02

CRUD

  • Create (INSERT)
  • Read (SELECT)
  • Update (UPDATE)
  • Delete (DELETE)

 

Create 구현

필요한 것

  • DB 테이블 생성(Domain → maven compile)
  • 필요한 정보를 가져다 줄 filter
  • View와 Controller(edit화면과 해당 뷰를 띄워줄 controller)
  • view와 controller를 연결할 repository, service

/java/com.OOOO/domain 폴더 아래에 본인이 만들고 싶은 domain 생성

❗ 나는 Project 도메인을 기준으로 잡았다. ❗

@Getter
@Setter
@Entity
@Table(name = "project", indexes = {})
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Project {
  //기본정보
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @EqualsAndHashCode.Include
  private Integer id;

  @JsonIgnore
  @DateTimeFormat(pattern = DateUtil.PATTERN_YMDHMS)
  @Column(nullable = false, insertable = false, updatable = false, columnDefinition = "timestamp(6) default current_timestamp(6)")
  private LocalDateTime createDate;   //생성일시

  @JsonIgnore
  @DateTimeFormat(pattern = DateUtil.PATTERN_YMDHMS)
  @Column(nullable = false, insertable = false, updatable = false, columnDefinition = "timestamp(6) default current_timestamp(6) on update current_timestamp(6)")
  private LocalDateTime updateDate;   //변경일시

  //추가정보
  @Column(nullable = false, length = 255)
  private String date; //프로젝트 진행날짜

  @Column(nullable = false)
  private String title; // 프로젝트 제목

  private String purpose; // 프로젝트 목적

  private String technology; // 프로젝트 사용기술

  private String address; // 프로젝트 깃헙주소

}

 

DB table에서 가져올 내용들을 filter로 가져온다. (/java/com.OOOO/filter)

❗ 나중에 filter를 통해 pageable 사용할 예정 ❗

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ProjectFilter {

  private String title;
  private String date;
  private String purpose;
  private String technology;
  private String address;
}

 

View 화면 생성(/resources/templates)

❗ 아래 코드는 현재 내가 진행하고 있는 프로젝트 코드이므로 그냥 바로 적용하면 깨질 것임. 따라서 알맞게 맞춰서 바꾸어줘야 함! ❗

<!DOCTYPE HTML>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<head>
  <th:block th:replace="fragments/head :: head"></th:block>
  <link rel="stylesheet" th:href="@{/static/assets/css/project-edit.css}" type="text/css"/>
  <style>
    h2 {
      font-weight: bold;
      margin-bottom: 20px;
    }
  </style>
</head>

<body class="is-preload">
<div id="wrapper">
  <th:block th:replace="fragments/top :: top"></th:block>
  <div id="main">
    <article id="work" class="panel">
      <h2>Project ADD</h2>
      <form method="post"
            th:action="|@{/project/save}|" th:object="${project}">
        <input th:field="*{id}" type="hidden"/>
        <button class="saveButton" type="submit" th:text="|save|"></button>
        <div class="mb-3">
          <label class="form-label" for="date">Progress Date</label>
          <input type="text" class="form-control" name="date" id="date" th:field="*{date}"
                 placeholder="프로젝트 진행 날짜를 입력해 주세요">
        </div>
        <div class="mb-3">
          <label class="form-label" for="title">Project Title</label>
          <input type="text" class="form-control" name="title" id="title" th:field="*{title}"
                 placeholder="프로젝트 제목을 입력해 주세요">
        </div>
        <div class="mb-3">
          <label class="form-label" for="purpose">Project Purpose</label>
          <input type="text" class="form-control" name="purpose" id="purpose" th:field="*{purpose}"
                 placeholder="프로젝트 목적을 입력해 주세요">
        </div>
        <div class="mb-3">
          <label class="form-label" for="content">Used Technology</label>
          <textarea class="form-control" rows="5" name="content" id="content"
                    th:field="*{technology}"
                    placeholder="사용한 기술을 입력해 주세요"></textarea>
        </div>
        <div class="mb-3">
          <label class="form-label" for="address">Github Address</label>
          <input type="text" class="form-control" name="address" id="address" th:field="*{address}"
                 placeholder="Github 주소를 입력해 주세요">
        </div>
      </form>
    </article>
  </div>
</div>
<th:block th:replace="fragments/footer :: footer"></th:block>
<th:block th:replace="fragments/common-script :: common-script"/>
</body>
</html>

 

이제 view와 연결 지을 controller 구현(/java/com.OOOO/controller)

❗ edit화면을 띄울 것과 적은 내용을 save 해서 DB에 저장이 되어야 함 ❗

@Controller
@RequiredArgsConstructor
@RequestMapping("/project")
public class ProjectController {

 @NonNull
  private final ProjectService projectService;
  
   @GetMapping({"/edit", "/edit/{id}"})
  public String edit(@PathVariable(required = false) Integer id, Model model) {

    Project project = (id == null) ? new Project() : projectService.findById(id).orElseThrow(
        DataNotFoundException::new);

    model.addAttribute("project", project);

    return "project/edit";
  }
  
   @PostMapping("/save")
  public String save(@ModelAttribute("project") Project project, BindingResult result, Model model,
      RedirectAttributes redirectAttr) {

    if (!result.hasErrors()) {
      projectService.save(project);
      redirectAttr.addFlashAttribute("message", "저장되었습니다.");
      return "redirect:/project/edit/" + project.getId();
    }
    model.addAttribute("project", project);
    return "project/edit";
  }
  
}

 

controller 안에 써있는 함수들을 구현해줘야 함!

제일 먼저 Repository 생성(/java/com.OOOO/repository)

@Repository
public interface ProjectRepository extends JpaRepository<Project, Integer>,
    CustomProjectRepository {
}

다음으론 customRepository 생성(/java/com.OOOO/repository/custom)

❗ findAllByFilter : filter를 통해 페이지를 구성할 계획 / 이것은 list를 뽑아낼 때 필요한 것 ❗

@NoRepositoryBean
public interface CustomProjectRepository {

  Page<Project> findAllByFilter(Pageable pageable, ProjectFilter filter);

}

마지막으론 RepositoryImpl 생성(/java/com.OOOO/repository/support)

❗ querydsl사용으로 코드로 db 코드를 만질 수 있다! ❗

public class ProjectRepositoryImpl extends QuerydslRepositorySupport implements
    CustomProjectRepository {

  private final QProject project = QProject.project;

  public ProjectRepositoryImpl() { super(Project.class); }

  @Override
  public Page<Project> findAllByFilter(Pageable pageable, ProjectFilter filter) {
    BooleanBuilder builder = new BooleanBuilder();

    if (!StringUtils.isBlank(filter.getDate())) {
      builder.and(project.date.containsIgnoreCase(filter.getDate()));
    }
    if (!StringUtils.isBlank(filter.getTitle())) {
      builder.and(project.title.containsIgnoreCase(filter.getTitle()));
    }
    if(!StringUtils.isBlank(filter.getAddress())){
      builder.and(project.address.containsIgnoreCase(filter.getAddress()));
    }
    if(!StringUtils.isBlank(filter.getTechnology())){
      builder.and(project.technology.containsIgnoreCase(filter.getTechnology()));
    }
    if(!StringUtils.isBlank(filter.getAddress())){
      builder.and(project.purpose.containsIgnoreCase(filter.getPurpose()));
    }

    final JPQLQuery<Project> query = from(project).where(builder);

    List<Project> result = getQuerydsl().applyPagination(pageable, query).fetch();

    return new PageImpl<>(result,pageable,query.fetchCount());

  }

}

 

repository 구성이 끝났다면 이를 controller에 가져다 사용할 수 있게 service를 구현(/java/com.OOOO/repository/service)

@Service
@RequiredArgsConstructor
public class ProjectService {

  @NonNull
  private final ProjectRepository projectRepository;

  public Optional<Project> findById(Integer id) { return projectRepository.findById(id); }

  public Page<Project> findAllByFilter(Pageable pageable, ProjectFilter filter) {
    return projectRepository.findAllByFilter(pageable, filter);
  }

  public Project save(Project project) {
    return projectRepository.save(project);
  }
}

 

현재까지 진행하면 나오는 결과

edit 화면

save 버튼을 누르면

DB 결과

DB에 저장이 됨을 확인할 수 있다.

 

 

❗ 혼자 진행 중인 프로젝트를 가져온 거라 아마 본인에 맞게 고쳐야 할 부분이 많을 것이다! 그래도 저 순서대로 하면 글 작성과 저장까지는 구현하는데 도움이 될지도...? 다음 포스팅은 R에 관해 구현할 예정 ❗

'Web > Spring' 카테고리의 다른 글

[설정] application.properties  (0) 2021.08.04
[CRUD] R구현  (0) 2021.08.02
[JPA] 데이터베이스 생성 또는 초기화  (0) 2021.08.02
[ERROR] Pageable import  (0) 2021.08.02
[ERROR] Querydsl import  (0) 2021.08.02

스프링을 처음 실행시키거나 DB를 초기화시킬 때 

datasource:
	initialization-mode: always
    
  jpa:
    hibernate:
      ddl-auto: create

위의 코드로 실행시켜주고

 

datasource:
	initialization-mode: never
    
  jpa:
    hibernate:
      ddl-auto: update

그 다음에 다시 바꾸어준다!

 

hibernate의 ddl-auto

  • udpate : 기존의 스키마를 유지하며 JPA에 의해 변경된 부분만 추가
  • validate : 엔티티와 테이블이 정상적으로 매핑되어있는지만 검증
  • create : 기존에 존재하는 스키마를 삭제하고 새로 생성
  • create-drop : 스키마를 생성하고 애플리케이션이 종료될 때 삭제
  • none : 초기화 동작을 하지 않음

 

❗ 도메인 파일에서 변경이 있을 때 해주면 좋다! local환경일 경우 local에서도 적용을 해줘야 하는 듯.. ❗

'Web > Spring' 카테고리의 다른 글

[CRUD] R구현  (0) 2021.08.02
[CRUD] C구현  (0) 2021.08.02
[ERROR] Pageable import  (0) 2021.08.02
[ERROR] Querydsl import  (0) 2021.08.02
[Util] ControllerNameInterceptor  (0) 2021.07.30

Controller에서 Pageable을 파라미터로 받아 사용하기 위해 import 되어야 할 것은

import org.springframework.data.domain.Pageable;

위의 코드와 같다!!

'Web > Spring' 카테고리의 다른 글

[CRUD] C구현  (0) 2021.08.02
[JPA] 데이터베이스 생성 또는 초기화  (0) 2021.08.02
[ERROR] Querydsl import  (0) 2021.08.02
[Util] ControllerNameInterceptor  (0) 2021.07.30
[배경] Querydsl  (0) 2021.07.28

BooleanBuilder를 찾을 수 없다고 오류가 뜬다. 이 때에는 import를 확인해봐야한다.

import com.querydsl.core.BooleanBuilder;

위와 같이 경로가 정확한지 판단한다!! querydsl에 대한 의존성을 pom.xml에 추가해두지 않으면 임의로 import 하기 때문에 pom.xml 파일을 꼭 확인해보길..

    <!--    Querydsl-->
    <dependency>
      <groupId>com.querydsl</groupId>
      <artifactId>querydsl-jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>com.querydsl</groupId>
      <artifactId>querydsl-apt</artifactId>
      <scope>provided</scope>
    </dependency>
    
     <!--      Querydsl-->
      <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>apt-maven-plugin</artifactId>
        <version>1.1.3</version>
        <executions>
          <execution>
            <goals>
              <goal>process</goal>
            </goals>
            <configuration>
              <outputDirectory>target/generated-sources/java</outputDirectory>
              <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
          </execution>
        </executions>
      </plugin>

 

❗ Query관련 Domain 설정 또한 의존성이 없으면 maven compile 해도 파일이 자동 생성이 안된다. ❗

'Web > Spring' 카테고리의 다른 글

[JPA] 데이터베이스 생성 또는 초기화  (0) 2021.08.02
[ERROR] Pageable import  (0) 2021.08.02
[Util] ControllerNameInterceptor  (0) 2021.07.30
[배경] Querydsl  (0) 2021.07.28
[배경] JPA  (0) 2021.07.27

템플릿마다 폴더 구성이 다르기 때문에 먼저 main화면부터 띄워서 구성을 확인해보는 게 좋다.

보통 index.html 파일이 메인화면일 가능성이 크다.

 

  • /resources 안으로 본인의 환경과 구성에 맞게 폴더들을 생성하고 파일들을 집어 넣어주면 된다.
    • 먼저 statictemplates 폴더를 생성한다.
    • templates에 뷰화면을 띄우는 html을 집어넣는다.
    • static에 css, image, js 등의 파일들을 넣는다.
  • /resources/templates안
    • controller에 맞게 폴더들 생성(뷰 화면)
    • fragments 폴더 생성(top menu나 footer와 같은 매 뷰마다 들어가는 것들)
  • /resources/static안
    • css, js, images, font를 자신의 생각대로 구성해 넣는다.

예시

 

현재 진행하고 있는 프로젝트의 resources폴더이다.

본인이 먼저 어떻게 정리할 건지 생각하고 진행하면 좋겠다.

 

❗ fragments 파일을 생성해두면 뷰 화면의 코드를 줄일 수 있어 좋다:) ❗

'Web > Front' 카테고리의 다른 글

[HTML, CSS] icon삽입  (0) 2021.08.02
[Javascript] window.location 객체  (0) 2021.07.30
[HTML] HTML 템플릿 다운로드 사이트  (0) 2021.07.30
[ERROR] 500에러 관련  (0) 2021.07.30
[ERROR] static파일 적용 관련  (0) 2021.07.30

+ Recent posts