본문 바로가기
코딩도전기/I.O.

CODO Day28_JAVA_I.O(SubStream)

by 코도꼬마 2023. 3. 13.

보조 스트림(최상위 클래스(주 스트림)의 하위 클래스)

  • 주 스트림과 연결되어 추가기능을 제공해주는 스트림
  • 사용하고 싶은 추가기능과 관련된 보조 스트림을 추가
  • 보조 스트림은 여러개를 한번에 사용할 수 있음(보통 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) 동영상시청 시 하얀바가 일정량 채워진 후 영상 재생

Written by zer0box

 

  • 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"/>
					&nbsp;&nbsp;
					<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="남"/>남
					&nbsp;&nbsp;&nbsp;&nbsp;
					<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객체의 내용을 보존 할 수 있음

Written by zer0box

 

  • 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