본문 바로가기

jsp,servlet,오라클DB를 이용한 게시판만들기

게시판만들기 테이블 [교수님이 코드리뷰해주신부분까지]

 

 

 

Optional<String> srt = Optional.ofNullable("test!!")

https://pamyferret.tistory.com/57

null일수도 잇는 값을 optional로 감싸주는 함수

 

null 처리를 도와주는 Optional<T>

개발을 하다보면 null 값 때문에 이런저런 오류들을 마주한다. 당연히 null 값이 아닐거라고 생각해서 사용하지만 객체의 경우는 기본적으로 nullable 하므로 얼마든지 null 일 수 있다. 만일 아래와

pamyferret.tistory.com

https://rabbitchris.tistory.com/40

 

java.sql.ResultSet 작업시 쿼리한 값이 있는지 없는지 확인, isBeforeFirst()

ResultSet 에 쿼리 결과를 가져온 다음에, 도대체가 값을 읽어온 것이 있는지 없는지 알려면 어떻게 해야 할까..? next() 메소드를 호출한 다음에 값이 있는지 확인하고 다시 첫번째로 돌리려고 first()

rabbitchris.tistory.com

result객체가 비어있지 않은지 null이 아닌지 확인하는 함수

rs.isBeforeFirst()

장점 : rs.next()와 달리 커서를 움직이지 않는다.

 

데이터베이스 사용하는 함수들

package project;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import utils.ConnectionHelper;

public class MemberDataBase implements MemberDAO{
	static {
		MemberService.setMemberDAO(new MemberDataBase());
	}
//select memberid from member where memberid=?
	@Override
	public boolean isExistUid(String uid) {
		Connection conn = ConnectionHelper.getConnection("oracle");
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select memberid from member where memberid=?";
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, uid);
			rs = pstmt.executeQuery();
			System.out.println("rs = "+rs);
			if(rs.next())return true;
//			else return false;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(pstmt);
			ConnectionHelper.close(rs);
		}
		
		return false;
	}
//insert into member(memberid,name,pwd,age,phone,address,gender) values(?,?,?,?,?,?,?)
	@Override
	public Member addMember(String uid, Member newMember) {
		Connection conn = ConnectionHelper.getConnection("oracle");
		PreparedStatement pstmt = null;
		int result = 0;
		String sql = "insert into member(memberid,name,pwd,age,phone,address,gender) values(?,?,?,?,?,?,?)";
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, uid);
			pstmt.setString(2, newMember.getName());
			pstmt.setString(3, newMember.getPwd());
			pstmt.setString(4, newMember.getAge());
			pstmt.setString(5, newMember.getPhone());
			pstmt.setString(6, newMember.getAddress());
			pstmt.setString(7, newMember.getGender());
			result = pstmt.executeUpdate();
			System.out.println("result = "+ result);
			return newMember;
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(pstmt);
		}
		
		return null;
	}
//	select memberid,name,pwd,age,phone,address,gender from member where memberid=?
	@Override
	public Member getMember(String uid) {
		Connection conn = ConnectionHelper.getConnection("oracle");
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select memberid,name,pwd,age,phone,address,gender from member where memberid=?";
		Member member = null;
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, uid);
			rs = pstmt.executeQuery();
			if(rs.next()) {
				member = Member.builder()
						.uid(rs.getString(1))
						.name(rs.getString(2))
						.pwd(rs.getString(3))
						.age(rs.getString(4))
						.phone(rs.getString(5))
						.address(rs.getString(6))
						.gender(rs.getString(7))
						.build();
				
			}
			return member;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(pstmt);
			ConnectionHelper.close(rs);
		}
		
		return null;
	}
// delete from member where memberid=?
	@Override
	public void removeMember(String uid) {
		Connection conn = ConnectionHelper.getConnection("oracle");
		PreparedStatement pstmt = null;
		String sql = "delete from member where memberid=?";
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, uid);
			pstmt.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(pstmt);
		}
		
	}
//	select memberid,name,pwd,age,phone,address,gender from member where name=? and phone=? 
	@Override
	public Optional<Member> findIDMember(String name, String phone) {
		Connection conn = ConnectionHelper.getConnection("oracle");
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select memberid,name,pwd,age,phone,address,gender from member where name=? and phone=?";
		Optional<Member> findMember = null;
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, name);
			pstmt.setString(2, phone);
			rs = pstmt.executeQuery();
			if(rs.next()) {
				Member member = Member.builder()
						.uid(rs.getString(1))
						.name(rs.getString(2))
						.pwd(rs.getString(3))
						.age(rs.getString(4))
						.phone(rs.getString(5))
						.address(rs.getString(6))
						.gender(rs.getString(7))
						.build();
				findMember = Optional.ofNullable(member);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(pstmt);
			ConnectionHelper.close(rs);
		}
		
		return findMember;
	}
// select memberid,name,pwd,age,phone,address,gender from member
	@Override
	public Map<String, Member> getMemberMap() {
		Connection conn = ConnectionHelper.getConnection("oracle");
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select memberid,name,pwd,age,phone,address,gender from member";
		Map<String,Member> memberMap = new HashMap();
		try {
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			while(rs.next()) {
				Member member = Member.builder()
						.uid(rs.getString(1))
						.name(rs.getString(2))
						.pwd(rs.getString(3))
						.age(rs.getString(4))
						.phone(rs.getString(5))
						.address(rs.getString(6))
						.gender(rs.getString(7))
						.build();
				memberMap.put(rs.getString(1), member);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(pstmt);
			ConnectionHelper.close(rs);
		}
		
		
		
		
		return memberMap;
	}
	
	@Override
	public void saveFileMemberMap() {
		
	}
	//update member set name=?,pwd=?,age=?,phone=?,address=?,gender=? from memberid=?
	@Override
	public Member updateMember(String uid,Member member) {
		Connection conn = ConnectionHelper.getConnection("oracle");
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "update member set name=?,pwd=?,age=?,phone=?,address=?,gender=? where memberid=?";
		
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, member.getName());
			pstmt.setString(2, member.getPwd());
			pstmt.setString(3, member.getAge());
			pstmt.setString(4, member.getPhone());
			pstmt.setString(5, member.getAddress());
			pstmt.setString(6, member.getGender());
			pstmt.setString(7, uid);
			pstmt.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return member;
	}

	
}

프로시저 불러오기

커서 반환

create or replace procedure usp_EmpList
(
p_sal IN number,
p_cursor OUT SYS_REFCURSOR -- 한건이상이면 메모리에 올려서 커서처럼 갖고 감
--java, c#언어에서 여러건의 데이터를 처리하려면 (커서타입을 사용해야한다.)
)
is
begin
    open p_cursor
    for select empno, ename , sal from emp where sal>p_sal;
end;
package R_DB_0719;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.kosa.utils.ConnectionHelper;

import oracle.jdbc.OracleTypes;

public class Cursor_Connection {
	public static void main(String[] args) {
		Connection conn = null;
		CallableStatement cstmt = null;
		ResultSet rs = null;
		String sql = "{call usp_EmpList(?,?)}";
		try {
			conn = ConnectionHelper.getConnection("oracle");
			cstmt = conn.prepareCall(sql);
			cstmt.setInt(1, 2000);
			cstmt.registerOutParameter(2, OracleTypes.CURSOR);
			boolean result = cstmt.execute();
			rs = (ResultSet)cstmt.getObject(2);
			while(rs.next()) {
				System.out.println(rs.getInt(1)+" "+rs.getString(2)+" "+rs.getInt(3));
			}
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(rs);
			ConnectionHelper.close(cstmt);
		}
	}
}

execute() - > 실행하고 하나이상의 ResultSet이 나올경우 true를 리턴

 

 

package R_DB_0719;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import com.kosa.utils.ConnectionHelper;

public class Error_print {

	public static void main(String[] args) {
		Connection conn = null;
		CallableStatement cstmt = null;
//		ResultSet rs=null;
		String sql = "{call usp_Insert_Emp(?,?,?,?)}";
		try {
			conn = ConnectionHelper.getConnection("oracle");
			cstmt = conn.prepareCall(sql);
			cstmt.setInt(1, 7777);
			cstmt.setString(2, "이연수");
			cstmt.setString(3,"baesu");
			cstmt.registerOutParameter(4, Types.VARCHAR);
			boolean result = cstmt.execute();
			String msg = (String)cstmt.getString(4);
			System.out.println(msg);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			ConnectionHelper.close(conn);
			ConnectionHelper.close(cstmt);
		}
		

	}

}

프로시저

create or replace procedure usp_Insert_Emp
(
    vempno IN emp.empno%TYPE,
    vename IN emp.ename%TYPE,
    vjob IN emp.job%TYPE,
    p_outmsg OUT varchar2
)
is
    begin
        insert into emp(empno, ename, job) values(vempno,vename,vjob);
        commit;
        p_outmsg :='SUCCESS';
        Exception when others then
            p_outmsg := SQLERRM;
            rollback;
end;

집에서 사용하던 프로젝트를 학원에서 하려면

프로젝트가 자동으로 서버에 업데이트 되는지 확인

 

프로젝트의 서버가 집과 다를 수있으므로 서버를 다시 bound 해준다.

.

서버가 내가 갖고 있는 서버에서 동작하는지 확인해 줘야한다.

project facets>dynamic web services > runtimes > apache-tomcat-9.0.71

classpath에 올리고 lib에 올리면 에러나기 쉬움 웹을 할때는 lib에 올려두는게 좋다

builder를 바로 써도됌 list에 넣을때

 

 

sQL문을 자바에서 작성할때는 엔터쳐서 보기 좋게 하는 편이 좋다.

엔터친 문자열에 앞뒤에 빈칸꼭넣어야함 콤마는 앞에->삭제할때 뒤쪽에 끝날때 콤마 없는거를 생각해주려고

 

view는 삽입삭제 수정이가능하고 이는 물리적테이블에도 반영된다. 사용자에게는 뷰에 대한 권한을 부여해서 물리테이블을 보호할 수있다 사용자는 실제 테이블이 어떻게 구성이 되어있는지 (join을 햇는지 어떤테이블에서 왔는지 컬럼명이 어떤건지) 모른다. 이러한 테이블과 view와의 관계를 의존성 역전의 원칙이라고한다. 특별화된 테이블을 조합해서 일반화한 view를 만들어 이용하기 때문이다.

 

jsp에서 파일찾기

ctrl +shift+r

 

if가 이중 일때는 if(   &&    )해서 사용하는 편이 좋음

if(loginMember != null)
	if(loginMember.isAdmin())


/////////////////////////////////////////////////



if(loginMember != null && loginMember.isAdmin())

 

객체

 

 

 

홈페이지 메인에서 공지사항을 띄워줄때 만약에 읽어온 게시글이 없다면 없다는 표현을 해주는 태그를 넣어준다.

<table>
<%
    for(Board board : boardList){

%>
     <tr>

     <td><%=board.getBoardid()%></td>
     <td><a href='board/viewOneBoard.jsp?boardid=<%=board.getBoardid()%>'><%=board.getTitle()%></a></td>
     <td><%=board.getMemberid()%></td>
     </tr>
<%
    }
    if(boardList.size()==0){
%>
    <tr>
        <td colspan=3>현재 자료가 존재 하지 않습니다</td>
     </tr>
<%
    }
%>
</table>

관리자 권한으로 접근했는지 판단하기 위해서 사용자의 id를비교해주어야할때  null값비교로 에러가 나지 않도록 관리해야함이 관건이다

.

두개의 값을 비교한 값을 리턴하는 함수 

public boolean isAdmin() {
		return Objects.equals("root", uid);
	}

Objects.equals함수는 인자 두개가  null 값일 경우에는 true 를 리턴한다. 오류없이 비교해 주려면

public boolean isAdmin() {
		return uid!=null && Objects.equals("root", uid);
	}

Objects 에서는 nonNull과 isNull을 비교하는 함수를 제공한다

public static boolean isNull(Object obj) {
    return obj == null;
}
public static boolean nonNull(Object obj) {
    return obj != null;
}

스크립트 문에서 체크박스 하나를 선택하면 나머지 하위 체크박스를 전부 선택할 수있도록하는 js, 자바 스크립트 코드에서는 for문 말고도 forEach문을 사용하는 방법도 있다 forEach문에서는 =>를 써서 java의 스트림 함수들과 동일하게 사용한다.

<script type="text/javascript">
    let allChk = document.querySelector("#chk");
    let boardIds = document.querySelectorAll(".boardid");
    allChk.addEventListener("change", function() {
/*	    	
        for (let i = 0; i < boardIds.length; i++) {
            chkBox[i].checked = allChk.checked;
        }
*/            
    	boardIds.forEach(e => e.checked = allChk.checked);
	});
	
</script>

글 삭제를 할때 url 로 전달해주는 get방식을 사용하면 용량이 작아서 여러 글을 삭제하고 싶을때 그 값들을 넘겨줄수 없다 그래서 get 방식에서 post 방식으로 변경하면 된다.

<form action="deleteSelectPage.jsp" method='post'>

글을 여러개 가져와서 sql문을 통해서 dB로 삭제 할 게시글의 번호를 넘겨주고 싶을때 StringBuilder를 사용해서 파라미터로 넘겨받아온 변수들을 이어준다. 그리고 sql문에 붙여주면 완성

오라클 특징 : 오라클은 String값으로 넘겨줘도 int랑 잘 비교해준다. 여러건의데이터를 넘겨줄때유용한 부분이다.

select * from board where boardid in('400216','400206','400204','400202','400200');
select * from board where boardid in(400216,400206,400204,400202,400200);

위의 두 쿼리는 boardid을 int값과 String 값으로 비교해본건데 둘다 동일하게 결과가 나온다.

public void deleteBoards(String[] boardidList) {
			Connection conn = ConnectionHelper.getConnection("oracle");
			Statement stmt= null;
			StringBuilder params = new StringBuilder();
			
			if(boardidList.length >= 1) {
				params.append("('");
				params.append(boardidList[0]);
				for(int i=1;i<boardidList.length;i++) {
					params.append("','").append(boardidList[i]);
				}
				params.append("')");
			}
			
			String sql = "delete from board where boardid in "+params.toString();
			try {
				stmt = conn.createStatement();
				stmt.executeUpdate(sql);
				
				
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally {
				ConnectionHelper.close(stmt);
				ConnectionHelper.close(conn);
			}
			
		}

StringBuilder를 사용해서 이어 붙여주는 방법은 위와 같은 방법이 가장빠르지만 아래와같은방법도 잇다.

//1. 마지막에 붙은 , 를 떼어내는 방법
for(String boardId : boardIds) {
    params.append(boardId).append(",");
}
if (params.length() == 1) {
    params.delete(params.length()-1, params.length());
}
//2. 이 방법은 값을 추가하면서 계속해서 boardidList의 길이까지 왔는지 확인하므로 성능이 안좋음
//남들 연산 한번할때 두번씩함;;; 비교, 추가
for(int i=0;i<boardIds.length;i++) { 
    params.append(boardIds[i]);
    if (i != boardIds.length-1) { 
        params.append(",");
    }
}

문자를 누적하는 방법은 StringBuilder와 StringBuffer가 잇는데 StringBuilder는 단일스레드로 가장빠르고 StringBuffer는 멀티스레드라서 느리다

 

그리고 스트림을 이용해서 문자열을 이어주는 방법도 있다.

 

Collectors.joining("구분자","처음시작문자","끝문자")

String params = Stream.of(boardIds).collect(Collectors.joining("','", "('", "')"));

 

jdbc를 수행할때 ResultSet - > PreparedStatement - > Connection 순으로 close해줘야한다. 아니면 정말 안좋은 코드

ConnectionHelper.close(rs);
ConnectionHelper.close(pstmt);
ConnectionHelper.close(conn);

 

게시글 등록이 로그인한 사용자만 가능하도록하는 js

<script>
    let insert = document.querySelector("#insertMember");
    insert.addEventListener("click",function(e){
        <%
        Member loginMember = (Member)session.getAttribute("loginMember");
        %>
        if(<%=loginMember%>==null){
            alert("로그인 후 이용해주세요");
            location.href="/myProject/index.jsp";
            e.preventDefault();
        }
    });
</script>

 

 

builder를 사용하면 객체 생성을 할 수 있다. 그래서 List에 add할때 build로 객체 생성해서 바로 추가하는 방법도 있다.

boardList.add(Board.builder()
        .boardid(rs.getInt("boardid"))
        .title(rs.getString("title"))
        .contents(rs.getString("contents"))
        .hit(rs.getInt("hit"))
        .memberid(rs.getString("memberid"))
        .fixed_yn(rs.getString("fixed_yn"))
        .build());

 

기본 값이 정해져 있는 속성값을 insert할 때에는 그냥 값을 하드코딩해주는 것이 좋다. 조회수 0, 현재시간, 게시글번호의 시퀀스값!!등등 그리고 sql문을 사용할때에는 ?에 뭐가 들어갈지 굉장히 직관 적이지 않고 뭔가를 추가하거나 삭제 할때의 편의 성을 위해서 엔터를 쳐주고 혹시모를 오류를 위해서 + 다음에 띄어쓰기 후 컬럼명을 써준다. 그리고 추가 삭제의 편의 성을 위해 컬럼명이나 ? 앞에 콤마(,)를 작성해준다.

 

String sql ="insert into board( " 
		             + "  boardid " 
		             + " ,title " 
		             + " ,contents "  
		             + " ,regdate "  
		             + " ,hit "  
		             + " ,boardtype "  
		             + " ,fixed_yn "  
		             + " ,memberid "  
		             + " ) values ( "  
		             + "  board_num.nextval "
		             + " ,? "
		             + " ,? "
		             + " ,sysdate "
		             + " ,0 "
		             + " ,? "
		             + " ,? "
		             + " ,?) ";