보조 스트림(최상위 클래스(주 스트림)의 하위 클래스)
- 주 스트림과 연결되어 추가기능을 제공해주는 스트림
- 사용하고 싶은 추가기능과 관련된 보조 스트림을 추가
- 보조 스트림은 여러개를 한번에 사용할 수 있음(보통 1~2개 정도)
Base | 주스트림 | 서브스트림 |
Byte Base | InputStream |
FileInputStream |
BufferInputStream | ||
DataInputStream | ||
ObjectInputStream | ||
OutputStream |
FileInputStream | |
BufferoutputStream | ||
DataoutputStream | ||
ObjectoutputStream | ||
Character Base | Reader | FileReader |
BufferReader | ||
DataReader | ||
Writer | FileWriter | |
BufferWriter | ||
DataWriter |
Buffered
- 전송받은 내용들을 일정량 모았다가 한번에 전송할 수 있도록 해주는 임시 저장소
- buffered 보조 스트림 생성시 8192byte(i/o) or 8192(r/w)자의 저장소가 생김
- ex) 동영상시청 시 하얀바가 일정량 채워진 후 영상 재생

- UploadController - 사진파일 읽어와서 출력하기(사진 업로드)
package kr.co.web.controller;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jihoon.file.utils.PartsUploadUtil;
@WebServlet("/write")
@MultipartConfig(fileSizeThreshold = 10*1024*1024,
maxFileSize = 50*1024*1024,
maxRequestSize = 100*1024*1024
)
public class UploadController extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PartsUploadUtil util = new PartsUploadUtil(req);
String fileName = util.getFileName("photo");
InputStream is = util.getStream("photo"); //주 스트림
BufferedInputStream bis = new BufferedInputStream(is); //보조 스트림
FileOutputStream fos = new FileOutputStream("C:/img/"+fileName); //주 스트림
BufferedOutputStream bos = new BufferedOutputStream(fos); //보조 스트림
long start = System.currentTimeMillis();
int data;
while((data = is.read()) != -1) {
fos.write(data);
}
long end = System.currentTimeMillis();
fos.flush();
fos.close();
is.close();
req.setAttribute("msg", (end-start)+"초 소요되었습니다.");
RequestDispatcher dis = req.getRequestDispatcher("index.jsp");
dis.forward(req, resp);
}
}
- index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style></style>
</head>
<body>
<form action="write" method="post" enctype="multipart/form-data">
<p>제목 : <input type="text" name="subject"/></p>
<p>설명 : <input type="text" name="desc"/></p>
<p>사진 : <input type="file" name="photo"/></p>
<p><input type="submit" name="저장"/></p>
</form>
</body>
<script>
var msg = "${msg}"
if(msg != ''){
alert(msg);
}
</script>
</html>
Data
- java의 데이터타입(int, boolean, long, double...) 데이터를 전송할 수 있도록 해줌(데이터타입 유지)
- String타입으로는 전송할 수 없고 UTF 사용
- 모든 type을 보내기 어려움이 있음(객체, 배열, 컬렉션 등)
return | return | ||
boolean | readBoolean( ) | void | writeBoolean(boolean v) |
double | readDouble( ) | void | writeDouble(double v) |
float | readFloat( ) | void | writeFloat(float v) |
int | readInt( ) | void | writeInt(int v) |
long | readLong( ) | void | writeLong(long v) |
short | readShort( ) | void | writeShort(short v) |
String | readUTF() | void | writeUTF(String v) |
- index.jsp - login&join page
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
table, th, td{
border: 1px solid black;
border-collapse: collapse;
padding: 5px 10px;
}
</style>
</head>
<body>
<h2>로그인</h2>
<form action="login" method="post">
<table>
<tr>
<th>ID</th>
<td><input type="text" name="id"></td>
</tr>
<tr>
<th>PW</th>
<td><input type="password" name="pw"></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" value="login"/>
<input type="button" value="회원가입" onclick="location.href='joinForm.jsp'"/>
</th>
</tr>
</table>
</form>
</body>
<script>
var msg = "${msg}";
if(msg != ''){
alert(msg);
}
</script>
</html>
- join.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
table, th, td{
border: 1px solid black;
border-collapse: collapse;
padding: 5px 10px;
}
</style>
</head>
<body>
<h2>로그인</h2>
<form action="join" method="post">
<table>
<tr>
<th>ID</th>
<td><input type="text" name="id"></td>
</tr>
<tr>
<th>PW</th>
<td><input type="text" name="pw"></td>
</tr>
<tr>
<th>이름</th>
<td><input type="text" name="name"></td>
</tr>
<tr>
<th>나이</th>
<td><input type="text" name="age"></td>
</tr>
<tr>
<th>성별</th>
<td>
<input type="radio" name="gender" value="남"/>남
<input type="radio" name="gender" value="여"/>여
</td>
</tr>
<tr>
<th>이메일</th>
<td><input type="email" name="email"></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" value="회원가입"/>
</th>
</tr>
</table>
</form>
</body>
<script>
var msg = "${msg}";
if(msg != ''){
alert(msg);
}
</script>
</html>
- MemberController
package kr.co.web.controller;
import java.io.IOException;
import java.util.HashMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.web.model.MemberModel;
@WebServlet(urlPatterns = {"/login","/join"})
public class MemberController extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String uri = req.getRequestURI();
String ctx = req.getContextPath();
String addr = uri.substring(ctx.length());
//System.out.println(uri + " / " + ctx + " / " + addr);
MemberModel model = new MemberModel();
String msg = "";
if(addr.equals("/join")) {
HashMap<String, String> param = new HashMap<String, String>();
param.put("id", req.getParameter("id"));
param.put("pw", req.getParameter("pw"));
param.put("name", req.getParameter("name"));
param.put("age", req.getParameter("age"));
param.put("gender", req.getParameter("gender"));
param.put("email", req.getParameter("email"));
//System.out.println(param);
msg = model.join(param);
}
if(addr.equals("/login")){
String id = req.getParameter("id");
String pw = req.getParameter("pw");
//System.out.println(id+"/"+pw);
msg = model.login(id, pw);
}
req.setAttribute("msg", msg);
RequestDispatcher dis = req.getRequestDispatcher("index.jsp");
dis.forward(req, resp);
}
}
- MemberModel
package kr.co.web.model;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
public class MemberModel {
//회원정보를 회원아이디 .dat 형태로 저장
//.dat : 이진데이터가 포함된 파일을 저장할 때 주로 사용
//DataOutputStream를 사용하여 이진데이터로 저장하기 때문에 .dat확장자를 사용
public String join(HashMap<String, String> params) {
//파일저장(파일쓰기-write)
//1.경로지정+File 객체화
File file = new File("C:/img/temp/"+params.get("id")+".dat");
String msg = "이미 존재하는 아이디입니다.";
if(!file.exists()) { //1-1. 같은 이름의 파일이 있으면 안됨
try {
//2.OutStream 준비(주+보조)
FileOutputStream fos = new FileOutputStream(file);
DataOutputStream dos = new DataOutputStream(fos);
//3.write() - 기록
dos.writeUTF(params.get("id"));
dos.writeUTF(params.get("pw"));
dos.writeUTF(params.get("name"));
int age = Integer.parseInt(params.get("age"));
dos.writeInt(age);
dos.writeUTF(params.get("gender"));
dos.writeUTF(params.get("email"));
//4.flush()
dos.flush();
//5.close()
dos.close();
msg = "회원가입이 완료되었습니다.";
} catch (Exception e) {
e.printStackTrace();
msg = "회원가입에 실패하였습니다. 다시 시도해주세요!";
}
}
return msg;
}
public String login(String id, String pw) {
String msg = "아이디 또는 비밀번호를 확인해주세요";
//1.경로지정 + 파일객체화
File file = new File("C:/img/temp/"+id+".dat");
if(file.exists()) { //1-1.같은 이름의 파일이 있어야함
//2.스트림 준비
try {
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = new DataInputStream(fis);
//3.읽어오기(쓴 순서대로 가져와야함)
String read_id = dis.readUTF();
String read_pw = dis.readUTF();
String read_name = dis.readUTF();
int read_age = dis.readInt();
String read_gender = dis.readUTF();
String read_email = dis.readUTF();
//System.out.println(read_id+"/"+read_pw+"/"+read_name+"/"+read_age+"/"+read_gender+"/"+read_email);
//4.자원닫기
dis.close();
if(id.equals(read_id) && pw.equals(read_pw)) {
msg = read_name + "님 로그인 되었습니다.";
}
} catch (Exception e) {
msg = "로그인 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요!";
e.printStackTrace();
}
}
return msg;
}
}
Object
- java의 최상위 객체인 Object를 다룰 수 있는 보조스트림
- 객체, 배열, 컬렉션 등 다양한 데이터 형태가 들어 갈 수 있음
- Class객체의 경우 직렬화(serialize) 하지 않으면 전달되지 않음(data의 크기를 예측할 수 없기 때문)
- 직렬화(serialize) : Object는 크기가 크기 때문에 스트림을 통해 내보내기에 어려움이 있어 쪼개서 내보냄
- 역직렬화(unserialize) : 찢어진 Object들을 원본형태로 맞추는 것
- List 데이터타입 클래스에 Serialiszable interface를 구현(implements) 해주어야함
- ArrayList를 파일로 저장함으로써 Java의 자료구조를 영구적으로 저장시킬 수 있음
- 서버가 종료되어도 Java객체의 내용을 보존 할 수 있음

- list.jsp - Board
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
table, th, td{
border: 1px solid black;
border-collapse: collapse;
padding: 5px 10px;
text-align: center;
}
button{
margin: 5px;
}
</style>
</head>
<body>
<button onclick="location.href='writeForm.jsp'">글쓰기</button>
<table>
<colgroup>
<col width="10%"/>
<col width="50%"/>
<col width="20%"/>
<col width="20%"/>
</colgroup>
<thead>
<tr>
<th>no</th>
<th>제목</th>
<th>작성자</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<c:if test="${list.size() == 0}">
<tr>
<th colspan="4">작성된 글이 존재하지 않습니다.</th>
</tr>
</c:if>
<!-- el태그에서는 객체 내 private 필드를 getter()를 사용하지 않고 꺼내올 수 있음 -->
<c:if test="${list.size() > 0}">
<c:forEach items="${list}" var="board" varStatus="stat">
<tr>
<td>${stat.index}</td>
<td><a href="detail?idx=${stat.index}">${board.subject}</a></td>
<td>${board.user_name}</td>
<td><button onclick="remove(${stat.index})">삭제</button></td>
</tr>
</c:forEach>
</c:if>
</tbody>
</table>
</body>
<script>
function remove(idx) {
location.href='remove?idx='+idx;
}
</script>
</html>
- writeForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
table, th, td{
border: 1px solid black;
border-collapse: collapse;
padding: 5px 10px;
/* text-align: center; */
}
button{
margin: 5px;
}
table{
width: 500px;
}
input[type="text"]{
width:100%;
}
textarea{
width: 100%;
height: 150px;
resize: none;
}
</style>
</head>
<body>
<form action="write" method="post">
<table>
<tr>
<th>작성자</th>
<td><input type="text" name="user_name"/></td>
</tr>
<tr>
<th>제목</th>
<td><input type="text" name="subject"/></td>
</tr>
<tr>
<th>내용</th>
<td><textarea name="content"></textarea></td>
</tr>
<tr>
<th colspan="2"><button>작성</button></th>
</tr>
</table>
</form>
</body>
<script></script>
</html>
- BoardController
package kr.co.web.controller;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.web.model.BoardModel;
@WebServlet(urlPatterns = {"/","/write","/detail","/remove"})
public class BoardController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dual(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dual(req,resp);
}
private void dual(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
req.setCharacterEncoding("UTF-8");
String uri = req.getRequestURI();
String ctx = req.getContextPath();
String addr = uri.substring(ctx.length());
BoardModel model = new BoardModel(req,resp);
switch (addr) {
case "/":
model.getList();
break;
case "/write":
model.wirte();
break;
case "/detail":
model.detail();
break;
case "/remove":
model.remove();
break;
}
}
}
- BoardModel
package kr.co.web.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class BoardModel {
HttpServletRequest req;
HttpServletResponse resp;
RequestDispatcher dis;
//ArrayList를 파일로 저장
private static ArrayList<BoardBean> list = null;
public BoardModel(HttpServletRequest req, HttpServletResponse resp) {
this.req = req;
this.resp = resp;
}
//리스트 부르기
public void getList() throws ServletException, IOException {
//System.out.println("list call");
readFile(); //파일로부터 ArrayList를 불러와 list변수 안에 넣기
req.setAttribute("list", list);
RequestDispatcher dis = req.getRequestDispatcher("list.jsp");
dis.forward(req, resp);
}
//파일에서 ArrayList 불러오기
private void readFile() throws IOException {
//1.경로지정
//2.파일 객체화(파일 있는지 확인 필수*)
File file = new File("C:/img/temp/bbs.dat");
if(file.exists()) {
//3.stream 준비
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis); //기본데이터타입 외에는 object로 해야함(ArrayList를 사용하기 때문)
//4.read()
try {
list = (ArrayList<BoardBean>) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
//5.close()
ois.close();
}else {
//최초사용의 경우 읽어올 파일이 없으므로 ArrayList를 생성해줌
list = new ArrayList<BoardBean>();
}
}
//글쓰기
public void wirte() throws ServletException, IOException {
String user_name = req.getParameter("user_name");
String subject = req.getParameter("subject");
String content = req.getParameter("content");
//System.out.println(user_name+"/"+subject+"/"+content);
BoardBean bean = new BoardBean();
bean.setUser_name(user_name);
bean.setSubject(subject);
bean.setContent(content);
list.add(bean);
writeFile();//ArrayList를 파일로 저장
getList(); //리스트 불러오기
}
private void writeFile() throws IOException {
//1.경로지정+파일 객체화
File file = new File("C:/img/temp/bbs.dat");
//2.스트림 준비
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//3.write()
oos.writeObject(list);
//4.flush()
oos.flush();
//5.close()
oos.close();
}
//상세보기
public void detail() throws ServletException, IOException {
String idx = req.getParameter("idx");
//System.out.println("detail : " + idx);
req.setAttribute("board", list.get(Integer.parseInt(idx)));
dis = req.getRequestDispatcher("detail.jsp");
dis.forward(req, resp);
}
//삭제하기
public void remove() throws ServletException, IOException {
String idx = req.getParameter("idx");
//System.out.println("remove : " + idx);
list.remove(Integer.parseInt(idx));
writeFile();
getList();
}
}
- BoardBean
package kr.co.web.model;
import java.io.Serializable;
//직렬화는 덩어리를 잘게 찢어보냄
//역직렬화는 찢어진 조각들을 맞춤
//규격(설명서)이 있어야 맞추는 것이 가능
//Serialiszable interface가 있어야 함
public class BoardBean implements Serializable{
private String subject;
private String user_name;
private String content;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
- detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
table, th, td{
border: 1px solid black;
border-collapse: collapse;
padding: 5px 10px;
/* text-align: center; */
}
table{
width: 500px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col width="20%"/>
<col width="80%"/>
</colgroup>
<tr>
<th>작성자</th>
<td>${board.user_name}</td>
</tr>
<tr>
<th>제목</th>
<td>${board.subject}</td>
</tr>
<tr>
<th>내용</th>
<td>${board.content}</td>
</tr>
<tr>
<th colspan="2"><button onclick="location.href='./'">목록</button></th>
</tr>
</table>
</body>
<script></script>
</html>
'코딩도전기 > I.O.' 카테고리의 다른 글
CODO Day29_JAVA_NIO(New Input / Output) (0) | 2023.03.14 |
---|---|
CODO Day27_JAVA_I.O(Stream/Upload) (0) | 2023.03.10 |
CODO Day26_JAVA_I.O(JAVA Input Output) (0) | 2023.03.09 |