TIL 0619

먼지·2024년 6월 19일

Today I Learned

목록 보기
80/89
post-thumbnail

실습

pom.xml

라이브러리 추가

	<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-validator</artifactId>
			<version>6.0.18.Final</version> 
		</dependency>

kr.spring.ch09.controller

Member Write Controller

package kr.spring.ch09.controller;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import kr.spring.ch09.vo.MemberVO;

@Controller
public class MemberWriteController {
	
	// 유효성 체크를 위한 자바빈(VO) 초기화
	@ModelAttribute("command")
	public MemberVO initCommand() {
		return new MemberVO();
	}
	
	// 폼 호출하기
	@GetMapping("/member/write.do")
	public String form() {
		return "member/write";
	}
	
	@PostMapping("/member/write.do")
	// valid 어노테이션을 작성하지 않으면 bindingresult의 값이 포함이 되지 않기 때문에 꼭 작성해야 한다
	public String submit(@ModelAttribute("command") @Valid MemberVO vo, BindingResult result) {
		
		System.out.println("전송된 데이터 : " + vo);
		
		if(result.hasErrors()) {
			return "member/write";
		}
		
		return "redirect:/index.jsp";
	}
}

kr.spring.ch09.vo

Member VO

package kr.spring.ch09.vo;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Range;


public class MemberVO {
	
	// 정규표현식으로 패턴 검사
	//  0~9, a~z, A~Z, + : 최소 한 번 이상 반복하라는 의미
	@Pattern(regexp="^[0-9a-zA-Z]+$")
	private String id;
	
	// 문자열의 길이를 지정한다
	// 최소 4자리, 최대 10자리까지
	@Size(min = 4, max = 10)
	private String password;
	
	// 필수 입력하도록 지정하기
	@NotEmpty
	private String name;
	
	// 이메일은 필수 입력, 이메일 형식에 맞게 작성하기
	@Email
	@NotEmpty
	private String email;
	
	// pom.xml에 라이브러리 추가한 이유는 range 어노테이션을 사용하기 위해서
	// 숫자 데이터 체크하기 - 최소 1, 최대 200
	@Range(min = 1 , max = 200)
	private int age;
	
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "MemberVO [id=" + id + ", password=" + password + ", name=" + name + ", email=" + email + ", age=" + age
				+ "]";
	}
	
	
}

Servlet - Context XML

<!-- 어노테이션을 이용한 유효성 체크 -->
	<beans:bean class="kr.spring.ch09.controller.MemberWriteController"/>

View - Member

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form:form action="write.do" modelAttribute="command">
아이디:		<form:input path="id"/>
			<form:errors path="id" cssStyle="color:red;"/>
			<br>
			
비밀번호:	<form:password path="password"/>
			<form:errors path="password" cssStyle="color:red;"/>
			<br>
			
이름: 		<form:input path="name"/>
			<form:errors path="name" cssStyle="color:red;"/>
			<br>
			
이메일: 	<form:input path="email"/>
			<form:errors path="email" cssStyle="color:red;"/>
			<br>
			
나이:		<form:input path="age"/>
			<form:errors path="age" cssStyle="color:red;"/>
			<br>
			
			<form:button>회원 가입</form:button>
	
</form:form>
</body>
</html>

Validation Properties

# 어노테이션을 이용한 유효성 체크시 에러 코드 - 에러 문구 지정
# 두가지 방법으로 가능함
#1) 어노테이션명 . 커맨드 객체 . 필드 
#2) 어노테이션명 . 필드
Pattern.id = 영문자와 숫자만 입력 가능합니다.
Size.password = 비밀번호는 최소 4자 ~ 최대 10자까지 입력 가능합니다.
NotEmpty.name = 이름은 필수 입력입니다.
Email.email = 이메일 형식에 맞게 입력 바랍니다.
NotEmpty.email = 이메일은 필수 입력입니다.
Range.age = 나이는 최소 1 ~ 최대 200까지 입력 가능합니다.
typeMismatch.age = 숫자만 입력 가능합니다(1~200)

Age를 integer형으로 입력 받았을 때
Integer는 필수 체크가 불가능
필수체크가 가능하도록 InitBinder 사용

Member VO

package kr.spring.ch09.vo;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Range;


public class MemberVO {
	
	// 정규표현식으로 패턴 검사
	//  0~9, a~z, A~Z, + : 최소 한 번 이상 반복하라는 의미
	@Pattern(regexp="^[0-9a-zA-Z]+$")
	private String id;
	
	// 문자열의 길이를 지정한다
	// 최소 4자리, 최대 10자리까지
	@Size(min = 4, max = 10)
	private String password;
	
	// 필수 입력하도록 지정하기
	@NotEmpty
	private String name;
	
	// 이메일은 필수 입력, 이메일 형식에 맞게 작성하기
	@Email
	@NotEmpty
	private String email;
	
	// pom.xml에 라이브러리 추가한 이유는 range 어노테이션을 사용하기 위해서
	// 숫자 데이터 체크하기 - 최소 1, 최대 200
	@Range(min = 1 , max = 200)
	private Integer age;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "MemberVO [id=" + id + ", password=" + password + ", name=" + name + ", email=" + email + ", age=" + age
				+ "]";
	}
	
}

Member Write Controller

package kr.spring.ch09.controller;

import javax.validation.Valid;

import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import kr.spring.ch09.vo.MemberVO;

@Controller
public class MemberWriteController {
	
	// 유효성 체크를 위한 자바빈(VO) 초기화
	@ModelAttribute("command")
	public MemberVO initCommand() {
		return new MemberVO();
	}
	
	// 폼 호출하기
	@GetMapping("/member/write.do")
	public String form() {
		return "member/write";
	}
	
	@PostMapping("/member/write.do")
	// valid 어노테이션을 작성하지 않으면 bindingresult의 값이 포함이 되지 않기 때문에 꼭 작성해야 한다
	public String submit(@ModelAttribute("command") @Valid MemberVO vo, BindingResult result) {
		
		System.out.println("전송된 데이터 : " + vo);
		
		if(result.hasErrors()) {
			return "member/write";
		}
		
		return "redirect:/index.jsp";
	}
	
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		// true - 요청 파라미터의 값이 null이거나 빈 문자열("")일 때 
		// 변환 처리를 하지 않고 null 값으로 할당한다.
		// false - 변환 과정에서 에러가 발생하고 에러 코드로 "typeMismatch"가 추가된다.
		binder.registerCustomEditor(Integer.class, new CustomNumberEditor(Integer.class, false));
	}
	
}

kr.spring.ch10.controller

파일 다운로드

Download Controller

서버에서 스트림을 만들어서 -> 클라이언트에 보내야 함
클래스에서 스트림을 만들어서 전송하는 작업을 해줘야함
뷰 작업은 뷰 리솔버 때문에 jsp를 사용해야 뷰라고 인식하기 때문에 설정을 바꿔줘야 한다

package kr.spring.ch10.controller;

import java.io.File;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class DownloadController {
	
	@RequestMapping("/file.do")
	// session을 통해서 절대 경로를 받을 수 있음
	public ModelAndView download(HttpSession session) {
		// file.txt의 컨텍스 경로상의 절대 경로를 구하기
		String path = session.getServletContext().getRealPath("/WEB-INF/file.txt");
		// 경로를 구한 후 파일 객체를 생성
		File downloadFile = new File(path);
							//	뷰 이름		속성명		 속성값			
		return new ModelAndView("download","downloadFile",downloadFile);
		// 새로운 뷰 리솔버 등록
	}
	
}

WEB-INF > file.txt

먼지댜

Servlet - Context XML

viewResolver의 기존 설정에 order로 설정 1순위로 변경을 해줘서 0순위인 viewResolver가 먼저 실행될 수 있도록 해준다.

파일 다운로드를 위한 viewResolver는 Bean의 이름과 View의 이름이 동일하다면 view가 생성될 수 있도록 설정을 해준다.

<!--============================== viewResolver 설정============================= -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
		<beans:property name="order" value="1" />
	</beans:bean>
	
	<!-- 파일 다운로드를 위한 viewResolver 설정 0순위로 설정(늘 먼저 동작) -->
	<!-- 빈의 이름과 뷰의 이름이 동일하다면 클래스더라도 해당 클래스를 호출 -->
	<beans:bean id="viewResolver" p:order = "0"
				class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
                
	<!-- 파일 다운로드 -->
	<beans:bean class="kr.spring.ch10.controller.DownloadController"/>
	<beans:bean id="download" class="kr.spring.ch10.view.DownloadView"/>

kr.spring.ch10.view

Download View

package kr.spring.ch10.view;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.FileCopyUtils;
import org.springframework.web.servlet.view.AbstractView;

public class DownloadView extends AbstractView{
	public DownloadView() {
		setContentType("application/download;charset=utf-8");
	}
	
	@Override
	protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		 File file = (File)model.get("downloadFile");
		 
		 response.setContentType(getContentType());
		 
		 response.setContentLength((int) file.length());
		 String fileName = new String(file.getName().getBytes("utf-8"),"iso-8859-1");
		 
		 response.setHeader("Content-Disposition", "attachment;filename=\"" +fileName+ "\";");
		 response.setHeader("Content-Transfer-Encoding", "binary");
		 
		 OutputStream out = response.getOutputStream();
		 
		 FileInputStream fis = null;
		 try {
			 	fis = new FileInputStream(file);
			 	FileCopyUtils.copy(fis, out);
			 	
		} finally {
			if(fis != null) try {fis.close();} catch (IOException e) {}
		}
		
		 out.flush();
		 
	}

}

Download View 코드 뜯어보기

실제로 뷰가 아니기 때문에 Abstract View를 상속받아서 작성을 해야한다.

Content 타입

  • 문서 타입을 지정해주는 것
  • 파일의 종류를 설정하면 다운로드가 가능해짐
public DownloadView() {
		setContentType("application/download;charset=utf-8");
	}

다운로드 하는 파일의 경로 정보가 저장된 File 객체를 반환해줘야 하는데 model에서 반환이 된다. 속성명을 통해서 속성값을 불러올 수 있게 해준다.

File file = (File)model.get("downloadFile");

위에서 지정했던 Content Type를 불러와서 지정해준다

response.setContentType(getContentType());

해당하는 content 의 용량을 지정하는데 파일의 길이만큼 지정을 해준다.

 response.setContentLength((int) file.length());

스트림은 목적지로부터 파일을 읽을 때 생성을 한다.
파일로부터 정보를 가져올 때는 fileinputstream, 파일을 생성할 때는 fileoutputstream을 사용한다.
경로로부터 파일을 읽어오기 때문에 스트림을 생성해야 한다.

파일명을 구하는 방법
getBytes로 가져올 때는 utf-8, 전체로는 iso-8859-1

 String fileName = new String(file.getName().getBytes("utf-8"),"iso-8859-1");

HTTP 응답 메세지 헤더를 세팅한다.
content-Disposition은 HTTP Response Body에 오는 컨텐츠의 기질/성향을 알려주는 속성이고, attachment를 주는 경우에는 body에 오는 값을 다운받으라는 뜻이다.
content-transfer-encoding은 전송되는 데이터의 안의 내용물들의 인코딩 방식이다.

response.setHeader("Content-Disposition", "attachment;filename=\"" +fileName+ "\";");
response.setHeader("Content-Transfer-Encoding", "binary");

파일을 읽어와서 보낼 때 outputStream 사용(파일 쓰기)

OutputStream out = response.getOutputStream();

파일을 읽어오는 과정 - 이미 위에 예외 던지는게 있기 때문에 catch 생성 X

FileInputStream fis = null;
	try {
		// 경로로부터 파일을 읽어옴
		fis = new FileInputStream(file);
			
		// inputstream에 있는걸 outputstream으로 쉽게 넘길 수 있음
		// 읽은 정보(fis)를 쓰기 정보(out)로 변환시켜 준다
		FileCopyUtils.copy(fis, out);
			 	
		} finally {
			if(fis != null) try {fis.close();} catch (IOException e) {}
		}
		
		 // 전송 작업 진행 (파일 전송)
		 out.flush();

엑셀 다운로드 & JSON 처리

pom.xml

라이브러리에 추가

	<dependency>
		    <groupId>org.apache.poi</groupId>
		    <artifactId>poi</artifactId>
			<version>3.13</version> 
		</dependency>

kr.spring.ch11.controller

Page Ranks Controller

package kr.spring.ch11.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import kr.spring.ch11.vo.PageRank;

@Controller
public class PageRanksController {
		
		// 엑셀 다운로드
		@RequestMapping("/pageRanksExcel.do")
		public ModelAndView handle() {
			List<PageRank> pageRanks = new ArrayList<PageRank>();
			pageRanks.add(new PageRank(1,"/board/list.do")); // 1위
			pageRanks.add(new PageRank(2,"/member/login.do")); // 2위
			pageRanks.add(new PageRank(3,"/cart/list.do")); // 3위
			
								// 뷰 이름		속성명		속성값
			return new ModelAndView("pageRanks", "pageRank" ,pageRanks);
		}
        
        // JSON 문자열 처리하기
		@RequestMapping("/pageJson.do")
		// view를 자동으로 생성해준다. list, map으로 만들어주면 JSON문자열로 처리를 자동해주는 어노테이션
		@ResponseBody
		public List<PageRank> parseJson() {
			List<PageRank> pageRanks = new ArrayList<PageRank>();
			pageRanks.add(new PageRank(1,"/file.do"));
			pageRanks.add(new PageRank(2,"/pageRanksExcel.do"));
			pageRanks.add(new PageRank(3,"/pageJson.do"));
			
			return pageRanks;
		}
	
}

kr.spring.ch11.vo

PageRank

package kr.spring.ch11.vo;

public class PageRank {
	// 접속하는 횟수 DB 저장	
	private int rank;
	private String page;

	public PageRank() {}
	
	// 생성자 정의 
	public PageRank(int rank, String page) {
		this.rank = rank;
		this.page = page;
	}
	
	public int getRank() {
		return rank;
	}
	public void setRank(int rank) {
		this.rank = rank;
	}
	public String getPage() {
		return page;
	}
	public void setPage(String page) {
		this.page = page;
	}
	@Override
	public String toString() {
		return "PageRank [rank=" + rank + ", page=" + page + "]";
	}
	
}

kr.spring.ch11.view

Page Rank View

package kr.spring.ch11.view;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.servlet.view.document.AbstractXlsView;

import kr.spring.ch11.vo.PageRank;

public class PageRanksView extends AbstractXlsView{
// 엑셀 파일을 다운 받을 수 있는 abstractxlsview를 상속받도록한다

	@Override
	protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		// 메소드 단위로 명시하기! (코드 읽기가 쉬워짐)
		// 시트 생성
		HSSFSheet sheet = createFirstSheet((HSSFWorkbook) workbook);
		
		// 열 이름 생성
		createColumnLabel(sheet);
		
		// 표시할 데이터 생성 
		List<PageRank> pageRanks = (List<PageRank>)model.get("pageRank");
		
		// 0번은 이미 사용되었기 때문에 1번부터 시작할 수 있도록 지정
		int rowNum = 1;
		for(PageRank rank : pageRanks) {
							// 시트 불러오고, 자바빈 불러오고, rowNum은 증가해야하기 때문에 ++도 함께 표시
			createPageRankRow(sheet, rank, rowNum++);
		}
		// 현재 메소드에서 알아서 다 처리 해주기 때문에 스트림 처리는 할 필요가 없음
			
		String fileName = "pageRanks2024.xls";
		response.setHeader("Content-Disposition", "attachment;filename=\"" +fileName+ "\";");
		response.setHeader("Content-Transfer-Encoding", "binary");
	}

	
	// 시트 생성
	private HSSFSheet createFirstSheet(HSSFWorkbook workbook) {
		// sheet 객체 생성
		HSSFSheet sheet = workbook.createSheet();
		
		// sheet 이름 지정   // sheet index, 이름
		workbook.setSheetName(0, "페이지 순위");
		
		// 특정 컬럼에 넓이를 지정
						// column index, width
		sheet.setColumnWidth(1, 256*20);
		
		return sheet;
	}
	
	// 열 이름 생성 -> 생성된 시트를 받아서 열 이름 생성
	private void createColumnLabel(HSSFSheet sheet) {
		HSSFRow firstRow = sheet.createRow(0);
		HSSFCell cell = firstRow.createCell(0);
		cell.setCellValue("순위");
		
		cell=firstRow.createCell(1);
		cell.setCellValue("페이지");
	}
	
	// 표시할 데이터 생성								// 순서값을 받아 순서에 맞게 데이터 정렬
	private void createPageRankRow(HSSFSheet sheet, PageRank rank, int rowNum) {
		HSSFRow row = sheet.createRow(rowNum);
		HSSFCell cell = row.createCell(0);
		cell.setCellValue(rank.getRank());
		
		cell = row.createCell(1);
		cell.setCellValue(rank.getPage());
	}
	
}

Servlet - Context XML

<!-- 엑셀 파일 다운로드 -->
	<beans:bean class="kr.spring.ch11.controller.PageRanksController"/>
	<beans:bean id="pageRank" class="kr.spring.ch11.view.PageRanksView"/>


JSON 문자열 처리하기 결과 화면

ch09 Spring JDBC

pom. xml

	<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
			<version>5.1.5.RELEASE</version> 
		</dependency>
		<dependency>
		    <groupId>commons-dbcp</groupId>
		    <artifactId>commons-dbcp</artifactId>
			<version>1.3</version> 
		</dependency>
		<dependency>
		    <groupId>commons-pool</groupId>
		    <artifactId>commons-pool</artifactId>
			<version>1.3</version> 
		</dependency>
		<dependency>
		    <groupId>commons-collections</groupId>
		    <artifactId>commons-collections</artifactId>
			<version>3.1</version> 
		</dependency>
		<dependency>
		    <groupId>com.oracle.database.jdbc</groupId>
		    <artifactId>ojdbc8</artifactId>
			<version>19.7.0.0</version> 
		</dependency>
		<dependency>
		    <groupId>com.atomikos</groupId>
		    <artifactId>transactions</artifactId>
			<version>3.9.3</version> 
		</dependency>

webapp > resources 폴더 생성, sql 폴더 생성, index 생성
resources > css 폴더 생성 후 style.css 추가
sql > table.sql 추가

Table.sql

CREATE table aboard(
num number primary key,
writer varchar2(30) not null,
title varchar2(60) not null,
passwd varchar2(12) not null,
content clob not null,
reg_date date not null
);

create sequence aboard_seq;

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	response.sendRedirect(request.getContextPath()+"/list.do");
%>

kr.spring.board.vo

BoardVO

package kr.spring.board.vo;

import java.sql.Date;


public class BoardVO {
	
	private int num;
	private String writer;
	private String title;
	private String passwd;
	private String content;
	private Date reg_date;

	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Date getReg_date() {
		return reg_date;
	}
	public void setReg_date(Date reg_date) {
		this.reg_date = reg_date;
	}
	@Override
	public String toString() {
		return "BoardVO [num=" + num + ", writer=" + writer + ", title=" + title + ", passwd=" + passwd + ", content="
				+ content + ", reg_date=" + reg_date + "]";
	}
	
	
}

kr.spring.board.controller

Board Controller

package kr.spring.board.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import kr.spring.board.vo.BoardVO;

@Controller
public class BoardController {
	
	// 유효성 체크를 위한 폼 초기화
	@ModelAttribute
	public BoardVO initCommand() {
		return new BoardVO();
	}
	
	@RequestMapping("/list.do")
	public ModelAndView process() {
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("selectList");
		
		return mav;
	}
	
	// 폼 호출하기
	@GetMapping("/insert.do")
	public String form() {
		return "insertForm";
	}
	
}

Views

selectList.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 목록</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css" type="text/css">
</head>
<body>
	<div class="page-main">
		<h2>게시판 목록</h2>
		<div class="align-right">
			<input type="button" value="글쓰기" onclick="location.href='insert.do'">
		</div>
	</div>
</body>
</html>

insertForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css" type="text/css">
</head>
<body>
	<div class="page-main">
		<h2>글 쓰기</h2>
		<form:form action="insert.do" modelAttribute="boardVO">
			<ul>
				<li>
					<form:label path="writer">작성자</form:label>
					<form:input path="writer"/>
					<form:errors path="writer" cssClass="errror-color"/>
				</li>
				<li>
					<form:label path="title">제목</form:label>
					<form:input path="title"/>
					<form:errors path="title" cssClass="errror-color"/>
				</li>
				<li>
					<form:label path="passwd">비밀번호</form:label>
					<form:password path="passwd"/>
					<form:errors path="passwd" cssClass="errror-color"/>
				</li>
				<li>
					<form:label path="content" >내용</form:label>
					<form:textarea path="content" cols="5" rows="20"/>
					<form:errors path="content" cssClass="errror-color"/>
				</li>
			</ul>
			<div class="align-center">
				<form:button>등록</form:button>
				<input type="button" value="목록" onclick="location.href='list.do'">
			</div>
		</form:form>
	</div>
</body>
</html>

Servlet - Context

빈 자동 스캔

<!-- Controller 빈 자동 스캔 -->
	<context:component-scan base-package="kr.spring.board.controller"/>
	<resources mapping="/resources/**" location="/resources/" /> 

index 실행시켰을 때 -> list.do로 이동(selectList.jsp가 실행)

글쓰기 버튼 눌르면 insert.do로 이동(insertForm.jsp가 실행)

profile
Lucky Things🍀

0개의 댓글