07. 자바빈(JavaBean)
개요
- JSP의 디자인 부분과 비즈니스 로직 부분을 분리함으로써 복잡한 JSP 코드들을 줄이고 프로그램의 재사용성을 증가시킴.
- 예) 회원정보라는 클래스를 설계하여 해당 클래스에 이름과 주소를 속성으로 정의하여 한 명의 회원 정보로 다루는 것. (멤버 vo)
설계규약
- 멤버 변수마다 별도의 get/set 메소드가 존재해야 함.
- get 메소드는 파라미터가 존재하지 않아야 함.
- set 메소드는 반드시 하나 이상의 파라미터가 존재해야 함.
- 빈즈 컴포넌트의 속성은 반드시 읽기 또는 쓰기가 가능해야 함. (public. 특히 get메소드!)
- 인자 없는 생성자가 반드시 있어야 함.
- 멤버 변수의 접근 제어자는 private이며, 각 get/set 메소드의 접근 제어자는 public으로 정의되어야 하며 클래스의 접근 제어자는 public으로 정의함.
BeanTest.java
package test;
public class BeanTest {
private String name = "홍길동";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<jsp:useBean/> 태그
- 자바빈 객체를 생성하기 위한 액션 태그.
형식: <jsp:useBean id="빈 이름" class="자바빈 클래스명" scope="사용 범위"/>
- 클래스명은 패키지 경로까지. scope의 기본 값은 page.
<jsp:setProperty/> 태그
- 자바빈 클래스의 속성 값을 설정하기 위한 태그.
형식 : <jsp:setProperty name="빈 이름" property="속성명" value="설정할 속성 값"/>
- 자바빈 객체의 멤버 변수를 직접 수정하는 것이 아니고, set 메소드를 호출하여 멤버 변수를 수정하는 것.
beanTest1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>2021. 3. 18. 오전 9:49:18</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<jsp:useBean id="myBean" class="test.BeanTest" scope="request"/>
<h3><%=myBean.getName()%></h3>
<h3>${myBean.name}</h3>
<jsp:setProperty property="name" name="myBean" value="일길동"/>
<h3><%=myBean.getName()%></h3>
<h3>${myBean.name}</h3>
</body>
</html>
- id는 변수명
- scope : 이 변수가 어디까지 살아있을지
- ${myBean.name} : BeanTest.java에 게터가 있어서 가능
BeanTest2.java
package test;
import lombok.Data;
@Data
public class BeanTest2 {
private String name;
private String addr;
private String email;
private String birthday;
}
beanTest2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>2021. 3. 18. 오전 10:23:54</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<form action="beanTest3.jsp" method="post">
<p>이름 <input type="text" name="name"></p>
<p>주소 <input type="text" name="addr"></p>
<p>이메일 <input type="email" name="email"></p>
<p>생년월일 <input type="date" name="birthday"></p>
<button>입력</button>
</form>
</body>
</html>
- .jsp input의 name은 .java에 있는 private 변수랑 똑같아야 함.
beanTest3.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>2021. 3. 18. 오전 10:27:24</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<jsp:useBean id="test2" class="test.BeanTest2"/>
<jsp:setProperty property="*" name="test2"/>
<p>${test2}</p>
</body>
</html>
- beanTest2.jsp를 실행하면 자동으로 beanTest3.jsp도 실행 됨.
매 번 한글처리하기 귀찮으니 filter를 만들어 줌. pdf 66쪽
CharsetFilter.java
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@WebFilter("/*")
public class CharsetFilter implements Filter{
private FilterConfig fc;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
arg0.setCharacterEncoding("utf-8");
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
fc = arg0; // 필터 객체 생성. 초기화 작업
}
}
TimeLogFilter.java
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@WebFilter("/*")
public class TimeLogFilter implements Filter{
private FilterConfig fc;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
arg0.setCharacterEncoding("utf-8");
System.out.println(arg0.getRemoteHost());
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
fc = arg0; // 필터 객체 생성. 초기화 작업
}
}
- 위 내용 복붙하고 doFilter에 println만 추가.
- 사용할 프로젝트에 패키지 filter 자체를 넣으면 됨.
09. 예외처리
pdf 114쪽, 교재 295쪽
page 지시자의 errorPage 속성 사용
<%@ page errorPage = "파일이름.jsp"%>
calc.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>2021. 3. 18. 오전 11:24:18</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<form action="calcResult.jsp">
<input type="number" name="num1"> /
<input type="number" name="num2">
<button>계산하기</button>
</form>
</body>
</html>
calcResult.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" errorPage="thrownpage.jsp"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>2021. 3. 18. 오전 11:24:18</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<%
int num1 = Integer.parseInt(request.getParameter("num1"));
int num2 = Integer.parseInt(request.getParameter("num2"));
int result = num1 / num2;
%>
<h3>결과는 <%=result %>입니다.</h3>
</body>
</html>
- errorPage="thrownpage.jsp" -> 결과 페이지에 하는 것.
thrownpage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isErrorPage="true"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>2021. 3. 18. 오전 11:36:52</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<%
if(exception instanceof ArithmeticException){
out.println("<h3>0으로 나눌 수 없습니다. </h3>");
}
if(exception instanceof NumberFormatException){
out.println("<h3>숫자를 입력하세요. </h3>");
}
%>
</body>
</html>
- isErrorPage="true"로 바꿔줌. 기본 false
instanceof : 연산자
피연산자들의 타입?
exception은 객체, ArithmeticException은 클래스
instanceof의 결과 boolean
10. 파일 업로드
<form method="post" enctype="multipart/form-data">
<input type="file" name="myfile">
<button>전송</button>
</form>
- enctype을 지정하지 않으면 파일 객체가 전송되는 것이 아니고 파일 이름만 문자열 형태로 서버로 전솜됨.
업로드 모듈 cos 라이브러리
o'reilly 오라일리라는 출판사가 만듦.
MultipartRequest
COS 라이브러리에서 가장 핵심적인 역할을 하는 클래스.
파일 업로드를 직접적으로 담당.
input.jsp
<%@page import="java.io.File"%>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@page import="java.util.UUID"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>2021. 3. 18. 오후 12:08:56</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<input type="text" name="id">
<input type="text" name="name">
<input type="file" name="myfile">
<button>전송</button>
</form>
<%=request.getMethod() %>
<%=request.getRealPath("/upload") %>
<%
if(request.getMethod().equals("POST")) {
MultipartRequest multi = new MultipartRequest(request, request.getRealPath("/upload"), 2 * 1024 * 1024, "utf-8", new DefaultFileRenamePolicy());
String id = multi.getParameter("id");
String name = multi.getParameter("name");
out.println(id);
out.println(name);
String fileSystemName = multi.getFilesystemName("myfile");
String originalFilename = multi.getOriginalFileName("myfile");
String type = multi.getContentType("myfile");
File file = multi.getFile("myfile");
out.println("<br>");
out.println(fileSystemName + "<br>");
out.println(originalFilename + "<br>");
out.println(type + "<br>");
out.println(file.length() + "<br>");
}
%>
<img alt="" src="upload/8.png">
</body>
</html>
- 객체 생성만 했을 뿐인데 업로드가 됨.
MultipartRequest multi = new MultipartRequest(request, request.getRealPath("/upload"), 2 * 1024 * 1024, "utf-8", new DefaultFileRenamePolicy());
- WebContent에 upload라는 폴더를 만들어 두고 실행해서 파일 등록 하면 RealPath(경로)에 파일 생김. 이클립스 upload 폴더에는 안 생김!
- getFilesystemName() : 서버에 실제로 업로드된 파일의 이름 반환
- getOriginalFileName() : 클라이언트가 업로드한 파일의 원본 이름 반환
- getContentType() : 업로드된 파일의 마임 타입을 반환
aws 서버에 올려보기.
chapter10을 war로 expert해서 aws에 올림.
(C:\Program Files\Apache Software Foundation\Tomcat 8.5\webapps)
ngnix 서버 잠시 내려 두고,
C:\Program Files\Apache Software Foundation\Tomcat 8.5\conf에서 8080검색 후 태그 잘 보고 80으로 바꿔줌.
Configure Tomcat 실행 후 서버 start
localhost/chapter10/input.jsp 잘 되면 levinni.site/chapter10/input.jsp를 로컬 컴퓨터에서 실행해도 들어가짐.
톰캣 서버에서 파일을 올렸을 때 realpath랑 로컬컴에서 올렸을 떄realpath랑 다름.
회원제 게시판 만들기(01)
1. SQL Developer에서 테이블 생성.
CREATE TABLE BOARD(
BOARDNO NUMBER CONSTRAINT BOARD_PK PRIMARY KEY
, TITLE VARCHAR2(2000)
, CONTENT CLOB
, USERID CONSTRAINT BOARD_MEMBER_FK REFERENCES MEMBER(USERID)
, REGDATE DATE DEFAULT SYSDATE
, HITCOUNT NUMBER DEFAULT 0
, PARENTNO CONSTRAINT BOARD_PARENTNO_FK REFERENCES BOARD(BOARDNO)
);
CREATE SEQUENCE SEQ_BOARD;
CREATE TABLE REPLY (
REPLYNO NUMBER CONSTRAINT REPLY_PK PRIMARY KEY
, CONTENT VARCHAR2(4000)
, USERID CONSTRAINT REPLY_MEMBER_FK REFERENCES MEMBER(USERID)
, REGDATE DATE DEFAULT SYSDATE
);
CREATE SEQUENCE SEQ_REPLY;
-- 게시글 작성, 목록 조회, 상세 조회, 글 수정, 글 삭제
INSERT INTO BOARD(BOARDNO, TITLE, CONTENT, USERID, PARENTNO, CATEGORY)
VALUES (SEQ_BOARD.NEXTVAL, '글제목', '글내용', 'javava', NULL, 1);
SELECT BOARDNO, TITLE, CONTENT, USERID, REGDATE, HITCOUNT, PARENTNO, CATEGORY
FROM BOARD
WHERE CATEGORY = 1
ORDER BY 1 DESC;
-- 상세조회
SELECT BOARDNO, TITLE, CONTENT, USERID, REGDATE, HITCOUNT, PARENTNO, CATEGORY
FROM BOARD
WHERE BOARDNO = 1;
-- 글수정
UPDATE BOARD SET
TITLE = '수정된 제목'
, CONTENT = '수정된 내용'
, REGDATE = SYSDATE
WHERE BOARDNO = 1;
-- 글삭제
DELETE BOARD WHERE BOARDNO = 3;
2. 이클립스 member_board 프로젝트에 자바 파일들 정리
3, Board.java
package board.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Board {
private Integer boardno;
private String title;
private String content;
private String userid;
private String regdate;
private Integer hitcount;
private Integer parentno;
private Integer category;
public Board(String title, String content, String userid, Integer parentno, Integer category) {
super();
this.title = title;
this.content = content;
this.userid = userid;
this.parentno = parentno;
this.category = category;
}
}
- 매개변수가 있는 생성자(Generate constructor using Fields) 만들 때, boardno, regdate는 자동으로 DB에서 생성되고, hitcount도 기본값이 0이니깐 만들 필요 없음.
4-1. BoardService.java
package board.service;
import java.util.List;
import board.vo.Board;
public interface BoardService {
// 다섯 개의 기능
// CRRUD
void write(Board board);
List<Board> list(Integer category);
Board findBy(Integer boardno);
void modify(Board board);
void remove(Integer boardno);
}
- 인터페이스로 만들고 아래 파일에서 구현.
4-2. BoardServiceImpl.java
package board.service;
import java.util.List;
import board.vo.Board;
public class BoardServiceImpl implements BoardService{
@Override
public void write(Board board) {
// TODO Auto-generated method stub
}
@Override
public List<Board> list(Integer category) {
// TODO Auto-generated method stub
return null;
}
@Override
public Board findBy(Integer boardno) {
// TODO Auto-generated method stub
return null;
}
@Override
public void modify(Board board) {
// TODO Auto-generated method stub
}
@Override
public void remove(Integer boardno) {
// TODO Auto-generated method stub
}
}
5. BoardDao.java
package board.dao;
import java.sql.Connection;
import java.sql.JDBCType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import board.vo.Board;
import member.vo.Member;
import util.DBConn;
public class BoardDao {
public void write(Board board) {
Connection connection = DBConn.getConnection();
// 문장 작성
try {
// 전처리 문장을 선언
String sql = "INSERT INTO BOARD(BOARDNO, TITLE, CONTENT, USERID, PARENTNO, CATEGORY)\r\n" +
"VALUES (SEQ_BOARD.NEXTVAL, ?, ?, ?, ?, ?)";
// 전처리 문장 생성
PreparedStatement pstmt = connection.prepareStatement(sql);
int idx = 1;
pstmt.setString(idx++, board.getTitle());
pstmt.setString(idx++, board.getContent());
pstmt.setString(idx++, board.getUserid());
pstmt.setInt(idx++, board.getParentno());
pstmt.setInt(idx++, board.getCategory());
// 실행
pstmt.executeUpdate();
}
catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
BoardDao dao = new BoardDao();
// Board board = new Board("자바에서 쓴 글 제목", "자바에서 쓴 글 내용", "javava", 1, 1);
// dao.write(board);
dao.list(1).forEach(System.out::println);
}
public List<Board> list(Integer category) {
ArrayList<Board> result = null;
Connection conn = DBConn.getConnection();
String sql = "SELECT BOARDNO, TITLE, CONTENT, USERID, REGDATE, HITCOUNT, PARENTNO, CATEGORY\r\n" +
"FROM BOARD\r\n" +
"WHERE CATEGORY = ?\r\n" +
"ORDER BY 1 DESC";
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, category);
ResultSet rs = pstmt.executeQuery();
result = new ArrayList<Board>();
while(rs.next()) {
int idx = 1;
Board board = new Board();
board.setBoardno(rs.getInt(idx++));
board.setTitle(rs.getString(idx++));
board.setContent(rs.getString(idx++));
board.setUserid(rs.getString(idx++));
board.setRegdate(rs.getString(idx++));
board.setHitcount(rs.getInt(idx++));
board.setParentno(rs.getInt(idx++));
board.setCategory(rs.getInt(idx++));
result.add(board);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
public Board findBy(Integer boardno) {
// TODO Auto-generated method stub
return null;
}
public void modify(Board board) {
// TODO Auto-generated method stub
}
public void remove(Integer boardno) {
// TODO Auto-generated method stub
}
}
- setParentno는 null 값 처리가 안 돼서 후에 수정할 예정.
'JSP & Servlet' 카테고리의 다른 글
회원제 게시판(03), 파일첨부 21. 03. 22. (0) | 2021.03.22 |
---|---|
회원제 게시판(02), JSTL과 EL 21. 03. 19. (0) | 2021.03.19 |
index 페이지에서 로그인, 로그아웃 처리 21. 03. 17. (0) | 2021.03.17 |
회원가입, 로그인, 로그아웃 21. 03. 16. (0) | 2021.03.16 |
01장- JSP 입문, 03장- Servlet의 핵심 사항들, 05장- 내장 객체 조금 21. 03. 15. (0) | 2021.03.15 |