[비트교육센터][Spring] 스프링 31일차 jsp 게시판 만들기(1)
1. board 프로젝트 만들기
1. Maven Project 만들기
https://julian5383.tistory.com/212
[비트교육센터][Spring] 스프링 30일차 AOP, 스프링 MVC
1. AOP 프로그래밍 - AOP: 여러 객체에 공통으로 적용할 수 있는 기능을 분리해 재사용성을 높여주는 프로그래밍 기법이다. 1) pom.xml 설정하기 4.0.0 com.julian5383 AopProject 0.0.1-SNAPSHOT UTF-8 17 17 org.springfra
julian5383.tistory.com
- 해당 게시물의 2. 스프링 MVC - 2) 항목을 참고하면 된다. firstWeb이 아닌 board 프로젝트를 생성하고 Convert to Maven Project를 해주면 된다.
(다른 말이지만 톰캣 10버전부터는 jsp를 지원하지 않는다.)
2. pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.julian5383</groupId>
<artifactId>board</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.28</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
</project>
- 스프링 30일차 FirstWeb 프로젝트의 pom.xml에서 3개의 종속성을 더 추가한다.
- MyBatis: 자바 퍼시스턴스 프레임워크의 하나로 XML 서술자나 애너테이션을 사용하여 저장 프로시저나 SQL 문으로 객체들을 연결시킨다.
- MySQL Connector Java: 프로그램과 MySQL 데이터베이스를 연결해주는 프로그램이다.
3. Missing required sources folder
- 프로젝트를 불러오는 과정에서 Build Path의 문제로 새로운 환경에서 경로가 맞지 않아 뜨는 문제이다.
[1] 프로젝트 우클릭->Build Path->Configure Build Path...를 클릭한다.
[2] resources 폴더에 missing이라고 뜬다.
[3] 탐색기에서 해당 프로젝트 경로에 resources 폴더를 선언한다.
[4] 오류가 없어진 것을 확인할 수 있다.
4. MvcConfig.java
package com.julian5383.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer{
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// TODO Auto-generated method stub
configurer.enable();
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// TODO Auto-generated method stub
registry.jsp("/WEB-INF/views/",".jsp");//브라우저 상에서 접근 불가로 직접선언
}
}
- 30일차에서 jsp 파일경로에 대한 점두사, 점미사 선언 부분이다.
- WebMvcConfigurer 인터페이스를 상속하고 있다. @Configuration 어노테이션을 붙인 클래스 역시 컨테이너에 빈으로 등록되므로 MvcConfig 클래스는 WebMvcConfigurer 타입의 빈이 된다.
- @EnableWebMvc 어노테이션을 사용시 WebMvcConfigurer 타입인 빈 객체의 메소드를 호출해 MVC 설정을 추가한다.
4. 데이터베이스 만들기
create database onboard default character set utf8mb4;
grant all privileges on onboard.* to 'lastcoder'@'%';
grant all privileges on onboard.* to 'lastcoder'@'localhost';
flush privileges;
- MySql Workbench에서 onboard 데이터 베이스를 선언하고 lastcoder 계정에 권한을 할당한다.
use onboard;
CREATE TABLE noticeboard
( article_no INT auto_increment primary key,
title VARCHAR(100),
content VARCHAR(2000),
write_date timestamp DEFAULT current_timestamp,
write_id VARCHAR(50)
);
INSERT INTO noticeboard (title, content, write_date, write_id)
values('안녕하세요1','테스트 글1',default,'kim');
INSERT INTO noticeboard (title, content, write_date, write_id)
values('안녕하세요2','테스트 글2',default,'park');
INSERT INTO noticeboard (title, content, write_date, write_id)
values('안녕하세요3','테스트 글3',default,'lee');
select * from noticeboard;
- onboard 데이터베이스에 noticeboard 테이블을 만들고 데이터 3개를 넣는다.
5. 데이터베이스 연결, 쿼리문 만들기
[1] mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="com.julian5383.model.OnboardDto" alias="onboardDto" />
</typeAliases>
<!--자료형별 별칭 선언으로 OnboardDto 클래스(패키지 경로까지)를 onboardDto 별칭으로 기재한다.-->
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/onboard?useUnicode=true&characterEncoding=utf8" />
<property name="username" value="lastcoder" />
<property name="password" value="1234" />
</dataSource>
</environment>
</environments>
<!--mybatis에서 연동할 데이터베이스 정보(DB유형, DB이름, MySql id, MySql 비번)를 등록한다.-->
<mappers>
<mapper resource="noticeboard.xml" />
</mappers>
<!--사용하고자 하는 쿼리가 정의된 mapper파일을 등록한다.-->
</configuration>
- mybatis에서 사용될 데이터베이스를 연동하기 위한 설정값들이다.
[2] noticeboard.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 = "mapper.notice">
<resultMap id="noticeResult" type="onboardDto">
<result property="article_no" column="article_no"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<result property="write_date" column="write_date"/>
<result property="write_id" column="write_id"/>
<!-- property가 dto의 필드명과 일치해야함,
column은 데이터베이스의 칼럼명과 정확히 일치해야함 -->
</resultMap>
<select id="selectAllArticles" resultMap="noticeResult">
<![CDATA[
select * from noticeboard order by write_date desc
]]> <!-- xml로 인지하지 않고 패스한다. -->
</select>
<insert id="insertArticle" parameterType="onboardDto">
<![CDATA[
INSERT INTO noticeboard (title, content, write_date, write_id)
values(#{title},#{content},default,#{write_id})
]]>
</insert>
<select id="selectArticle" resultType="onboardDto" parameterType="int">
<![CDATA[
select * from noticeboard where article_no=#{article_no}
]]> <!-- xml로 인지하지 않고 패스한다. -->
</select>
</mapper>
- resultmap 태그는 dto 필드명들을 리스트 형태로 리턴해준다.
- resultType: select 된 데이터를 onboardDto 객체로 반환해준다.
- parameterType: 쿼리문에서 #{}에 들어갈 값이 타입을 정해준다.
- CDATA 안에 있는 쿼리는 XML로 인지하지 않고 문자열로 인식한다. 쿼리를 작성할때 xml에서 <,>,&을 태그로 인식해 에러를 발생시킬수 있는데 CDATA를 통해 해결할 수 있다.
6. 게시판 만들기
[1] OnboardDto.java
package com.julian5383.model;
public class OnboardDto {
private int article_no;
private String title;
private String content;
private String write_date;
private String write_id;
public int getArticle_no() {
return article_no;
}
public void setArticle_no(int article_no) {
this.article_no = article_no;
}
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 String getWrite_date() {
return write_date;
}
public void setWrite_date(String write_date) {
this.write_date = write_date;
}
public String getWrite_id() {
return write_id;
}
public void setWrite_id(String write_id) {
this.write_id = write_id;
}
}
- Dto(data transfer object): 프로세스 사이에서 데이터를 전송하는 객체이다.
- Persistence framework(지속성 프레임워크): 데이터의 저장, 조회, 변경, 삭제를 다루는 클래스 및 설정 파일들의 집합이다.
종류 1. sql mapping 방법
ex) mybatis: 자바 퍼시스턴스 프레임워크의 하나로 XML 서술자나 애너테이션(annotation)을 사용하여 저장 프로시저나 SQL 문으로 객체들을 연결시킨다.
종류 2. orm(object relational mapping) 방법
ex) Hibernate: 자바 언어를 위한 객체 관계 매핑 프레임워크이다. DB의 데이터와 코드를 매핑시켜주기 위한 프레임워크다.
- spring data jpa(java persistence api): 스프링에서 jpa를 사용할수 있게 해주는 프레임워크이다. 데이터베이스 사용시 쿼리가 아닌 객체로 다룬다.
[2] BoardDao.java
package com.julian5383.model;
import java.io.Reader;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class BoardDao {
private static SqlSessionFactory sessionFactory = null;
//DB와의 연결과 SQL 실행을 담당해주는 객체이다.
public static SqlSessionFactory getInstance() {
if (sessionFactory == null) {
try {
String resource = "mybatis-config.xml";
Reader reader = Resources.getResourceAsReader(resource);
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//mybatis-config.xml 파일을 사용한다.
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return sessionFactory;
}
public List<OnboardDto> selectAllArticles(){
sessionFactory = getInstance();
SqlSession session = sessionFactory.openSession();
List<OnboardDto> articleList = session.selectList("mapper.notice.selectAllArticles");
session.close();
return articleList;
}
//게시판에서 게시글리스트를 출력하는 클래스이다.
//noticeboard.xml에서 selectAllArticles id값을 가진 select 태그를 실행해 리스트를 출력한다.
public void insertArticle(OnboardDto onboardDto) {
sessionFactory = getInstance();
SqlSession session = sessionFactory.openSession();
session.insert("mapper.notice.insertArticle",onboardDto);
session.commit();
}
//게시판에서 게시물을 입력하는 메소드이다.
//세션: 스프링 애플리케이션과 데이터베이스의 연결통로
public OnboardDto selectArticle(int articleNo) {
sessionFactory = getInstance();
SqlSession session = sessionFactory.openSession();
OnboardDto article = session.selectOne("mapper.notice.selectArticle", articleNo);
session.close();
return article;
}
//게시판에서 상세페이지를 담당하는 메소드이다.
}
- Dao(data access object): 데이터베이스의 데이터에 접근하기 위한 객체이다.
[3] BoardService.java
package com.julian5383.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.julian5383.model.BoardDao;
import com.julian5383.model.OnboardDto;
public class BoardService {
@Autowired
BoardDao boardDao;
public List<OnboardDto> listArticles(){
List<OnboardDto> articleList = boardDao.selectAllArticles();
return articleList;
}
//게시글 리스트 조회를 담당하는 메소드이다.
public void addArticle(OnboardDto onboardDto) {
boardDao.insertArticle(onboardDto);
}
//게시물 입력을 담당하는 메소드이다.
public OnboardDto viewArticle(int articleNo) {
OnboardDto article = boardDao.selectArticle(articleNo);
return article;
}
//게시물 조회를 담당하는 메소드이다.
}
- Service: Dao가 DB에서 받아온 데이터를 전달받아 가공하는 클래스이다.
[4] BoardController.java
package com.julian5383.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.julian5383.model.OnboardDto;
import com.julian5383.service.BoardService;
@Controller //내부적으로 컨트롤러 역할을 할수 있게한다.
@RequestMapping("/board") //board 주소를 시작으로 다른 메소드 주소에 접근한다.
public class BoardController {
@Autowired
BoardService boardService;
@Autowired
OnboardDto onboardDto;
List<OnboardDto> articleList;
//list경로(list가 없어도 됨)로 요청이 들어오면 해당 메소드와 매칭
//boardService 객체의 listArticles 메소드를 호출한다.
//해당 메소드에 있는 게시글들을 list.jsp의 items="data_list"인 태그에 출력한다.
@RequestMapping({"/list", "/"})
public String getArticleList(Model model) {
articleList = boardService.listArticles();
model.addAttribute("data_list",articleList);
return "list";
}
//글쓰는 페이지이다.
@RequestMapping("/add")
public String writeArticle() {
return "write";
}
//글을 쓰고 저장하는 페이지이다.
//onboardDto 객체에 title, content, bit값을 넣고
//boardService의 addArticle로 입력한다.
//입력후 list페이지로 돌아간다.
//@RequestParem을 통해 write.jsp에 i_title, i_content name을 가진 태그에 입력된 내용을 가져온다.
@PostMapping("/addArticle")
public String addArticle(@RequestParam(value="i_title")String title, @RequestParam(value="i_content")String content) {
onboardDto.setTitle(title);
onboardDto.setContent(content);
onboardDto.setWrite_id("bit");
boardService.addArticle(onboardDto);
return "redirect:list";
}
//게시글 조회 메소드이다.
//articleNo를 통해서 페이지 번호로 받는다.
//ModelAndView를 통해 view.jsp파일에 해당 게시글을 출력한다.
//"article"라는 키를 통해서 onboardDto의 값들을 출력한다.
@GetMapping("/view")
public ModelAndView viewArticle(@RequestParam(value="no")String articleNo) {
onboardDto = boardService.viewArticle(Integer.parseInt(articleNo));
ModelAndView mv = new ModelAndView();
mv.setViewName("view");
mv.addObject("article", onboardDto);
return mv;
}
//model.addAttribute를 통해서 게시글을 출력할 수 있다.
// @GetMapping("/view")
// public String viewArticle2(Model model,@RequestParam(value="no")String articleNo) {
// onboardDto = boardService.viewArticle(Integer.parseInt(articleNo));
// model.addAttribute("article", onboardDto);
// return "view";
// }//둘다 똑같음
}
- Controller: View와 Model(비즈니스 로직)을 연결해주는 다리 역할을 한다.
[5] BoardConfig.java
package com.julian5383.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.julian5383.controller.BoardController;
import com.julian5383.model.BoardDao;
import com.julian5383.model.OnboardDto;
import com.julian5383.service.BoardService;
@Configuration
public class BoardConfig {
@Bean
public OnboardDto onboardDto() {
return new OnboardDto();
}
@Bean
public BoardDao boardDao() {
return new BoardDao();
}
@Bean
public BoardService boardService() {
return new BoardService();
}
@Bean
public BoardController boardController() {
return new BoardController();
}
}
- 컨트롤러에 선언한 @Autowired가 스프링 컨테이너에 등록한 빈에게 의존관계주입이 필요하기 때문에 BoardConfig.java에 onboardDto, boardDao, boardService, boardController를 빈으로 추가한다.
- @autowired 사용시 @bean을 이용해 해당 자리에 주입된 메소드가 무엇인지 알아야 한다.
7. jsp 파일 만들기
[1] list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!--http://localhost:8080이 context주소-->
<%
request.setCharacterEncoding("UTF-8");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 목록</title>
<style>
.cls1{
text-decoration: none;
}
.cls2{
text-align: center;
font-size: 30px;
display: block;
}
</style>
</head>
<body>
<table align="center" border="1" width="80%">
<thead>
<tr height="10" align="center" bgcolor="lightgreen">
<th>글번호</th>
<th>작성자</th>
<th>제목</th>
<th>작성일</th>
</tr>
<c:choose>
<c:when test="${empty data_list}">
<!--게시물이 없을 경우 해당 <c>태그를 출력한다.-->
<tbody>
<tr height="10">
<td colspan="4">
<p align="center">
<b><span style="font-size: 9pt;">등록된 글이 없습니다.</span></b>
</p>
</td>
</tr>
</tbody>
</c:when>
<c:otherwise>
<tbody>
<c:forEach var="article" items="${data_list}" varStatus="articleNum">
<!--게시물이 있을 경우 해당 <c>태그를 출력한다.-->
<tr align="center">
<td width="5%">${articleNum.count}</td>
<td width="10%">${article.write_id}</td>
<td align="left">
<span style="padding-right: 30px;"></span>
<a class="cls1" href="${contextPath}/board/view?no=${article.article_no}">
${article.title}
</a>
<!--게시물 상세페이지로 이동한다.-->
</td>
<td width="10%">${article.write_date}</td>
</tr>
</c:forEach>
</tbody>
</c:otherwise>
</c:choose>
</thead>
</table>
<a class="cls1" href="${contextPath}/board/add"><span class="cls2">글쓰기</span></a>
<!--write.jsp로 이동한다.-->
</body>
</html>
- contextpath에는 board가 있다.
- contextpath는 절대경로를 의미한다.
- article은 컨트롤러에 선언한 article 키값을 통해서 게시판 리스트를 출력한다.
- <a>태그가 있는 곳에는 ${article.article_no}은 데이터베이스에 입력된 열의 id값이다. 이 id를 통해서 특정 게시물로 이동한다.
[2] view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<%
request.setCharacterEncoding("UTF-8");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상세 조회</title>
<script>
function backToList(frm){
frm.action="${contextPath}/board/list";
//contextPath = board
frm.submit();
}//list.jsp로 이동한다.
//frm.submit에 수정된 게시물을 제출하는 것이다.(다음 게시물에 작성예정)
function fn_enable(frm){
document.querySelector('#i_title').disabled=false;
document.querySelector('#i_content').disabled=false;
document.querySelector('#tr_btn').style.display='none';
document.querySelector('#tr_btn_modify').style.display='table-row';
}//fn_enable 함수가 있는 태그를 클릭시 i_title, i_content의 disabled가 해제된다.
//tr_btn의 id를 가진 태그들이 사라진다.
//tr_btn_modify의 id를 가진 태그들이 띄어진다.
</script>
<style>
#tr_btn_modify{
display:none;
}
</style>
</head>
<body>
<form name="articleForm" method="post" action="">
<table border="0" align="center">
<tbody> <!--list.jsp에 이동했을때 <a>태그의 id값에 따라 특정 게시물 내용을 출력한다.-->
<tr>
<td width="150" align="center" bgcolor="#FF9933">글번호</td>
<td>
<input type="text" value="${article.article_no}" disabled>
<input type="hidden" value="${article.article_no}" name="articleNo">
</td>
</tr>
<tr>
<td width="150" align="center" bgcolor="#FF9933">작성자</td>
<td>
<input type="text" value="${article.write_id}" name="writer" disabled>
</td>
</tr>
<tr>
<td width="150" align="center" bgcolor="#FF9933">제목</td>
<td>
<input type="text" value="${article.title}" name="title" id="i_title" disabled>
</td>
</tr>
<tr>
<td width="150" align="center" bgcolor="#FF9933">내용</td>
<td>
<textarea rows="20" cols="60" name="content" id="i_content" disabled>
${article.content}
</textarea>
</td>
</tr>
<tr>
<td width="20%" align="center" bgcolor="#FF9933">작성일</td>
<td>
<input type="text" value="${article.write_date}" disabled>
</td>
</tr>
<tr id="tr_btn">
<td colspan="2" align="center">
<input type="button" value="수정" onclick="fn_enable(articleForm)">
<!--수정 버튼을 눌렀을때 fn_enable 함수에 있는 내용들이 동작한다.-->
<input type="button" value="삭제"
onclick="fn_remove('${contextPath}/board/remove','${article.article_no}')">
<!--해당 게시물을 삭제한다.(다음 게시글에서 설명예정)-->
<input type="button" value="목록보기" onclick="backToList(articleForm)">
<!--list.jsp로 이동한다.-->
</td>
</tr>
<tr id="tr_btn_modify">
<td colspan="2" align="center">
<input type="button" value="저장" onclick="fn_modify_article(articleForm)">
<!--fn_modify_article 함수가 동작한다.(다음 게시물에서 설명예정)-->
<input type="button" value="취소" onclick="backToList(articleForm)">
<!--list.jsp로 이동한다.-->
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
[3] write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<%
request.setCharacterEncoding("UTF-8");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 쓰기</title>
<script>
function backToList(frm){
frm.action="${contextPath}/board/list";
//contextPath = board
frm.submit();
}
//list.jsp로 이동하는 함수이다.
</script>
<style>
.class-caption {
width:100px;
}
.class-content {
width:500px;
}
</style>
</head>
<body>
<h1 style="text-align: center;">글 쓰기</h1>
<form name="articleForm" method="post" action="${contextPath}/board/addArticle">
<!--<form> 태그의 action 속성은 폼 데이터(form data)를 서버로 보낼 때 해당 데이터가 도착할 URL을 명시한다.-->
<table border="0" align="center">
<tbody>
<tr>
<td align="right" class="class-caption">글제목: </td>
<td colspan="2">
<input type="text" maxlength="100" name="i_title" class="class-content">
</td>
</tr>
<tr>
<td align="right" valign="top" class="class-caption">글내용: </td>
<td colspan="2">
<textarea name="i_content" rows="10" maxlength="2000" class="class-content"></textarea>
</td>
</tr>
<!--i_title, i_content는 controller의 addArticle 메소드에 값을 가져갈때 어느태그에서 가져갈지 명시해주는 역할을 한다. -->
<tr>
<td align="right"></td>
<td colspan="2">
<input type="submit" value="저장">
<!--게시물 입력완료시 제출하는 버튼이다.-->
<input type="button" value="목록보기" onclick="backToList(articleForm)">
<!--list.jsp로 이동한다.-->
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
- 새로운 게시글을 입력한다.
-->결과
1) 리스트
2) 글쓰기
3) 수정하기(다음 게시물에서 수정하기 구현 예정)