Day 95

ChangWoo·2023년 1월 17일
0

중앙 HTA

목록 보기
39/51

수정과 삭제

여러 단계에 걸친 Form 입력 처리하기

public class OrderForm {
	// 주문상품 정보
	private int productId;
	private int qty;
	// 배송지 정보
	private String postalCode;
	private String address1;
	private String address2;
	private String tel;
	private String memo;
	// 결재 정보
	private String payType;
	private String payNumber;
	private String cardMonth;
	private String cardYear;
	private String months;
	private String payAmount;
	...
}
// 요청핸들러 메소드에서 Model객체에 "orderForm"이라는 이름으로 저장되는 객체가 있으면, 그 객체는 세션에 "orderForm"이라는 속성명으로 저장시킨다.
@SessionAttributes({"orderForm"})
public class OrderController {	
	@PostMapping("/order/step-0")
	public String step0(Model model) {
		// OrderForm객체를 생성해서 model객체에 "orderForm"이라는 이름으로 저장한다.
		model.addAttribute("orderForm", new OrderForm());
		return "order/form-1";
	}
}
// 주문상품정보를 입력하고 서버로 제출한다.
order/form-1.jsp
<form method="post" action="/order/step-1">
	<input type="number" name="productId" value="100">
	<input type="number" name="qty" value="3">
	<button type="submit">다음</button>
</form>
@SessionAttributes({"orderForm"})
public class OrderController {	
	@PostMapping("/order/step-0")
	public String step0(Model model) {
		model.addAttribute("orderForm", new OrderForm());
		return "order/form-1";
	}
	// 주문상품 정보를 전달받는다.
	@PostMapping("/order/step-1")
	// 요청객체나 세션객체에 "orderForm"이라는 속성명으로 저장된 객체를 조회한다.
	// 앞 단계에서 세션객체 "orderForm"이라는 속성명으로 저장된 OrderForm객체를 가져온다.
	// 입력폼에서 전달한 주문상품정보를 orderForm객체의 멤버변수에 저장한다.
	public String step1(@ModelAttribute("orderForm") OrderForm orderForm) {		
		return "order/form-2";
	}
}
order/form-2.jsp
<form method="post" action="/order/step-2">
	<input type="text" name="postalCode" value="12345">
	<input type="text" name="address1" value="서울특별시 종로구 봉익동">
	<input type="text" name="address2" value="디아망빌딩 401호">
	<input type="text" name="tel" value="010-1111-1111">
	<input type="text" name="memo" value="사무실에 맡겨주세요">
	<button type="submit">다음</button>
</form>
@SessionAttributes({"orderForm"})
public class OrderController {
		@PostMapping("/order/step-0")
	public String step0(Model model) {
		model.addAttribute("orderForm", new OrderForm());
		return "order/form-1";
	}
	@PostMapping("/order/step-1")
	public String step1(@ModelAttribute("orderForm") OrderForm orderForm) {	
		return "order/form-2";
	}
	// 배송지 정보를 전달받는다.
	@PostMapping("/order/step-2")
	// 요청객체나 세션객체에 "orderForm"이라는 속성명으로 저장된 객체를 조회한다.
	// 앞/앞 단계에서 세션객체 "orderForm"이라는 속성명으로 저장된 OrderForm객체를 가져온다.
	// 입력폼에서 전달한 배송정보를 orderForm객체의 멤버변수에 저장한다.
	// 현재 OrderForm객체에는 주문상품정보와 배송지 정보가 저장되어 있다.
	public String step2(@ModelAttribute("orderForm") OrderForm orderForm) {		
		return "order/form-3";
	}
}
order/form-3.jsp
<form method="post" action="/order/step-3">
	<input type="radio" name="payType" value="card" checked>
	<input type="text" name="payNumber" value="1111-2222-3333-4444">
	<input type="text" name="cardMonth" value="04">
	<input type="text" name="cardYear" value="27">
	<input type="text" name="months" value="0">
	<input type="text" name="payAmount" value="7000"/>
	<button type="submit">주문완료</button>
</form>
@SessionAttributes({"orderForm"})
public class OrderController {	
	@PostMapping("/order/step-0")
	public String step0(Model model) {
		model.addAttribute("orderForm", new OrderForm());
		return "order/form-1";
	}
	@PostMapping("/order/step-1")
	public String step1(@ModelAttribute("orderForm") OrderForm orderForm) {		
		return "order/form-2";
        }
	// 결재정보를 전달받는다.
	@PostMapping("/order/step-3")
	// 요청객체나 세션객체에 "orderForm"이라는 속성명으로 저장된 객체를 조회한다.
	// 앞/앞/앞 단계에서 세션객체 "orderForm"이라는 속성명으로 저장된 OrderForm객체를 가져온다.
	// 입력폼에서 전달한 결재정보를 orderForm객체의 멤버변수에 저장한다.
	// 현재 OrderForm객체에는 주문상품정보, 배송지 정보, 결재정보가 저장되어 있다.
	public String step3(@ModelAttribute("orderForm") OrderForm orderForm, SessionStatus sessionStatus) {
		// 주문상품정보, 배송지정보, 결재정보가 저장된  OrderForm객체를 서비스에 전달하고, 업무로직을 호출해서 주문처리를 수행시킨다.
		orderService.createOrder(orderForm);
		// SessionStatus객체는 세션에 저장된 객체를 삭제한다.
		// 단, SessionStatus는 이 컨트롤러의 @SessionAttribues 어노테이션에서 지정한 속성명으로 저장된 객체만 삭제한다.
		sessionStatus.setComplete();
		return "redirect:success";
	}
}
  • 여러 개의 Form을 하나의 Form 안에 저장시킬 수 있다.

  • 수정은 조회/변경이다.
  • SessionAttributes :
  • ModelAttribute :
### 게시글 수정정보: PostModifyForm [no=97, userId=null, title=수정 연습, content=수정 연습 내용, readCount=0, commentCount=0, deleted=null, createdDate=null, updatedDate=null]
  • 새로 만들었기 때문에 값이 null이다.

수정하기

PostController
@GetMapping("/modify")
	public String modifyform(@RequestParam("postNo") int postNo, Model model) {
		PostDetailDto dto = postService.getPostDetail(postNo); 		
		PostModifyForm form = new PostModifyForm();
		BeanUtils.copyProperties(dto, form);		
		model.addAttribute("modifyPost", form);		
		return "post/modify-form";
	}	
	@PostMapping("/modify")
	public String modify(@ModelAttribute("modifyPost") PostModifyForm postModifyForm) {
		System.out.println("### 게시글 수정정보: " + postModifyForm);
		postService.updatePost(postModifyForm);
		return "redirect:detail?postNo=" + postModifyForm.getNo();
	}
PostModifyForm.java
package com.sample.web.request;
import java.sql.Date;
public class PostModifyForm {
	private int no;
	private String userId;
	private String title;
	private String content;
	private int readCount;
	private int commentCount;
	private String deleted;
	private Date createdDate;
	private Date updatedDate;	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public int getReadCount() {
		return readCount;
	}
	public void setReadCount(int readCount) {
		this.readCount = readCount;
	}
	public int getCommentCount() {
		return commentCount;
	}
	public void setCommentCount(int commentCount) {
		this.commentCount = commentCount;
	}
	public String getDeleted() {
		return deleted;
	}
	public void setDeleted(String deleted) {
		this.deleted = deleted;
	}
	public Date getCreatedDate() {
		return createdDate;
	}
	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}
	public Date getUpdatedDate() {
		return updatedDate;
	}
	public void setUpdatedDate(Date updatedDate) {
		this.updatedDate = updatedDate;
	}	
	@Override
	public String toString() {
		return "PostModifyForm [no=" + no + ", userId=" + userId + ", title=" + title + ", content=" + content
				+ ", readCount=" + readCount + ", commentCount=" + commentCount + ", deleted=" + deleted
				+ ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]";
	}	
}
PostService.java
public void updatePost(PostModifyForm postModifyForm) {
		Post post = new Post();
		BeanUtils.copyProperties(postModifyForm, post);		
		postMapper.updatePost(post);		
	}
modify-form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<title>애플리케이션</title>
</head>
<body>
<c:set var="menu" value="post" />
<%@ include file="../common/navbar.jsp" %>
<div class="container my-3">
	<div class="row mb-3">
		<div class="col">
			<h1 class="fs-4 border p-2 bg-light">게시글 수정</h1>
		</div>
	</div>
	<div class="row mb-3">
		<div class="col">
			<p>제목과 내용을 입력하세요</p>
			<form class="border bg-light p-3" method="post" action="modify">
				<!-- 히든필드에 게시글 번호를 설정한다. -->
				<input type="hidden" name="no" value="${modifyPost.no }" />
				<div class="mb-2">
					<label class="form-label">제목</label>
					<input type="text" class="form-control" name="title" value="${modifyPost.title }"/>
				</div>
				<div class="mb-2">
					<label class="form-label">내용</label>
					<textarea rows="4" class="form-control" name="content">${modifyPost.content }</textarea>
				</div>
				<div class="text-end">
					<a href="detail?postNo=100" class="btn btn-secondary btn-sm">취소</a>
					<button type="submit" class="btn btn-primary btn-sm">수정</button>
				</div>
			</form>
		</div>
	</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</body>
</html>

실행결과(수정 전)

실행결과(수정 중)

실행결과(수정 후)

Spring과 Spring Boot

  • Spring
  • 자바 엔터프라이즈 애플리케이션 개발을 지원하는 오픈소스 프레임워크다.

  • 특징
    * POJO(Plain Old Java Object)을 사용해서 자바엔터프라이즈 애플리케이션 개발을 개발한다.
    POJO - 순수 자바객체
    특별한 외부 라이브러리를 가져와서 사용하지 않는 자바객체
    특별한 실행환경에 종속되지 않는 자자객체
    POJO는 재사용하기 쉽다.
    POJO는 테스트하기 쉽다.
    POJO는 코드가 단순하고, 디버깅하기 쉽다.
    Service/ Vo 객체등이 POJO다.

  • 순수 자바객체 = EJB가 제공하는 기능들을 사용하는데 그 기능을 사용하면 Old가 아니므로 스프링을 통해 완전 Old로 돌아가보자는 취지
    IoC/DI의 구현체다.
    IoC(Inversion of control:제어역전)
    자신이 사용할 객체를 스스로 생성하지 않고, 외부로부터 전달받거나, 생성된 객체를 검색해서 사용하는 것을 말한다.
    제어역전은 자신이 사용할 객체를 획득하는 방법이 역전(뒤바꼈다)되었다는 의미다.
    Spring Container는 IoC의 구현체다.
    IoC의 종류
    의존성주입 - DI(Dependency Injection)
    의존성검색 - DP(Dependency Pull), DL(Dependency Lookup)
    DI(Dependency Injection:의존성주입)
    자신이 사용할 객체를 스스로 생성하지 않고, 제 3자(Spring Container)로부터 제공(주입)받는 것이다.
    스프링에서는 @Autowired를 이용해서 자동 의존성 주입을 지원한다.
    스프링과 스프링 컨테이너
    스프링은 프레임워크다.
    스프링 컨테이너는 구현 클래스다.
    스프링 컨테이너는 스프링 빈 설정정보를 읽어서 객체를 생성하고, 객체간의 의존관계를 파악해서 의존성 주입작업을 수행하는 객체다.

    • AOP의 구현체다.
      AOP(Aspect Oriented Programming)는 관점지향 프로그래밍이다.
      AOP는 기능을 공통관심사항(로깅, 트랜잭션처리, 예외처리)과 핵심관심사항(업무로직)으로 구분해서 개발하는 것이다.
      AOP는 공통관심사항을 별도의 클래스로 구현하고, 핵심관심사항이 구현된 메소드가 실행될 때 지정된 공통관심사항이 같이 실행되게 하는 것이다.
      AOP를 사용하면 개발자가 구현하는 메소드에는 핵심관심사항만 남아있게 된다.(개발자는 업무로직의 구현에만 집중하면 된다.)
      * 선언적 트랜잭션처리는 AOP를 이용한 것이다.
      AOP는 코드의 중복을 제거한다.
      AOP는 코드가 간결해지고, 유지보수를 쉽게한다.

    • 다양한 모듈로 구성되어 있다.
      Test 모듈
      spring-test : spring application에 대한 테스트를 지원한다.
      Core Container 모듈
      spring-beans, spring-core, spring-context : 객체 생성, 의존성 주입, 국제화처리 등을 지원하는 spring container를 제공한다.
      spring-expression : spring EL 지원한다.
      AOP 모듈
      spring-aop : 관점지향프로그래밍을 지원한다.
      DataAccess 모듈
      spring-jdbc : jdbc를 활용한 데이터베이스 엑세스를 지원한다.
      spring-tx : 트랜잭션처리를 지원한다.
      spring-orm : 객체-관계 매핑프레임워크(ORM:Object-Reational Mapping)와의 연동을 지원한다.
      객체와 테이블을 매핑해서 데이터베이스 엑세스 작업을 수행한다.
      Web 모듈
      spring-web : 웹 환경에 최적화된 spring container를 제공한다.
      spring-webmvc : MVC 패턴의 웹 애플리케이션개발을 지원한다.
      spring-websocket : 웹소켓기능을 지원한다.

  • spring boot
    • spring framework를 기반으로 하는 하위 프로젝트다.
    • XML이나 추가적인 코드 작성없이 바로 실행할 수 있는 독립 실행형 Spring Application을 빠르게 제작할 수 있도록 지원한다.
    • 특징
      - 독립 실행형 애플리케이션
      플랫폼(하드웨어나 운영체제)에 종속되지 않고 인터넷 연결이나 기타 서비스 설치없이 바로 작동하는 애플리케이션을 개발할 수 있다.
      - 내장형 서버
      Tomcat, Jetty 등의 내장형 서버를 포함하고 있다.
      - 의견 제시형 접근 방식의 개발
      의견 제시형 접근 방식을 이용해서 애플리케이션을 구성한다.
      의견 제시형 접근 방식은 소프트웨어 디자인에 있어서는 소프트웨어 개발자의 자유도를 제한해서 작업을 미리 지정된 방식으로 진행하도록 하는 것이다.
      - 자동구성
      프로젝트에 새로운 라이브러리가 포함될 때 마다 해당 라이브러리와 관련된 구성을 자동으로 수행한다
      새로운 라이브러리가 포함될 때 마다, 미리 정해진 방식으로 설정된 정보를 읽어서 자동으로 애플리케이션을 구성한다.

SpringBoot

  • 프로젝트명 / 빌드명 /자바버전 / 패키징 방식등을 지정한다.

home.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" 
	trimDirectiveWhitespaces="true"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<title>애플리케이션</title>
</head>
<body>
<div class="container">
   <h1></h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</body>
</html>

실행결과

  • spring과 달리 localhost 뒤에 /home를 붙이지 않아도 연결이 가능하다.

Mapper파일 생성

UserMapper.java
package com.example.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {	
}
users.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.mapper.UserMapper">
</mapper>
application.yml
server:
  port: 80                        # 톰캣서버의 port번호를 지정한다. 기본값은 8080이다. 0으로 지정하면 랜덤으로 지정된다.

logging:
level:
root: info # 애플리케이션의 기본 로그출력 레벨을 info로 지정한다.
'[com.example.mapper]': trace # com.example.mapper 패키지의 로그출력 레벨을 trace로 지정한다.

                              # mybatis가 실행하는 sql과 실행결과를 출력하게 한다.

spring:
datasource: # 커넥션 풀 설정을 지정한다.
url: jdbc:oracle:thin:@localhost:1521:xe
driver-class-name: oracle.jdbc.OracleDriver
username: hr
password: zxcv1234
mvc: # spring mvc 관련 설정을 지정한다.
view: # 뷰 페이지의 경로를 지정한다.
prefix: /WEB-INF/views/ # 뷰 이름 앞에 붙는 경로를 지정한다.
suffix: .jsp # 뷰 이름 뒤에 붙는 확장자를 지정한다.

mybatis:
mapper-locations:

  • mybatis/mappers/*.xml # mybatis의 mapper 파일의 경로를 설정한다.
    configuration:
    jdbc-type-for-null: null # null값이 허용되는 컬럼에 null값이 저장될 때 값의 타입을 null로 지정한다.
    log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl # mybatis 실행 로그를 출력할 구현클래스이름을 지정한다.
- Mapper 파일 비생성시 오류가 발생하므로 생성한다.
- yml과 properties가 많이 사용되지만 그 중에서도 yml이 많이 사용된다.
profile
한 걸음 한 걸음 나아가는 개발자

0개의 댓글