안경잡이개발자

728x90
반응형

  가끔 이클립스(Eclipse) 개발 환경에서 자바(Java) 개발을 하다 보면, 45초 서버 실행(Server Start) 제한 때문에 오류가 발생할 때가 있습니다. 45초 이내에 서버가 시작이 안 되면 문제가 있다고 보기 때문이에요. 다만 서버에 이것저것 라이브러리를 추가하다 보니까 어쩔 수 없이 서버가 실행되기까지 45초가 넘어가는 경우도 존재합니다. 그럴 때 45초 제한을 해제하는 방법을 알려드리고자 합니다.


오류 메시지: Server Tomcat v8.5 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.



  위와 같이 오류 문구가 발견되면, 다음과 같이 조치하시면 됩니다.



  이클립스의 아래 쪽에 'Servers' 란에 떠있는 서버를 더블 클릭하여 상세 정보를 확인합니다.



  이후에 위와 같이 'Timeouts' 탭을 누르시면 됩니다.



  그러면 위와 같이 Start 부분 및 Stop 부분의 시간을 늘릴 수 있습니다. 저는 Start 부분의 시간을 90초로 증가시키니까 문제가 해결되었네요.

728x90
반응형

Comment +3

728x90
반응형

  인텔리J (IntelliJ)자바(Java) 통합 개발 환경 중에서 가장 많이 사용되고 있는 것 중 하나입니다. 기본적으로 인텔리J는 유료 제품이지만 학생에 한해서 학생 인증을 수행하면 이를 무료로 이용할 수 있습니다. 이번 시간에는 학생 인증을 통해 무료로 설치하는 방법에 대해 알아보도록 하겠습니다. 현재 저도 대학생이라서 인텔리J를 무료로 사용할 수 있습니다.


1. 인텔리J 학생 인증 공식 사이트 접속: https://www.jetbrains.com/student/



  위와 같이 학생 라이선스 인증 사이트에 들어가서 등록 버튼을 누릅니다. 이후에 다음과 같이 자신의 정보와 '학교 이메일 주소'를 입력합니다. 일반적인 대학교는 웹 메일을 신청하면, 웹 메일 주소를 하나씩 할당해주는 방식을 사용할 것이므로 메일이 없으신 분은 자신의 학교에 요청을 하시면 됩니다.


2. 본인의 학생 정보 기입하기



3. 이메일 주소에서 인증 수행하기


  이후에 인증 메일이 도착하면 인증을 진행하면 됩니다.



4. 추가 이메일 인증 수행하기


  첫 번째 인증이 수행되면 다시 제대로 회원가입을 수행하기 위해서 활성화(Activate) 관련 이메일이 추가적으로 도착합니다. 여기에서 교육 라이선스(Educational License) 활성화를 진행해주시면 됩니다.



5. 회원가입 수행하기


  이제 본인이 사용할 계정 정보로 회원가입을 진행하시면 됩니다.



6. 인텔리J 소프트웨어 다운로드 사이트 접속https://www.jetbrains.com/idea/


  이제 인텔리J 소프트웨어를 설치해주시면 됩니다.



7. 설치 프로그램 다운로드


  학생은 기본적으로 인텔리J 얼티메이트(Ultimate) 버전을 무료로 이용할 수 있기 때문에 다음과 같이 얼티메이트 버전으로 다운로드를 진행해주시면 됩니다.



8. 인텔리J 설치 이후에 인증 및 실행


  인텔리J를 설치하고, 처음 실행하시면 초기 환경을 세팅하고 결과적으로 라이선스 인증을 하라는 메시지가 나옵니다. 그 때 계정 정보를 입력하고 인증하여 실행하시면 됩니다.




728x90
반응형

Comment +0

728x90
반응형

  이번 시간에도 지난 시간에 이어서 자바 FX(Java FX)를 이용한 서버 및 클라이언트 채팅 프로그램을 개발하도록 합시다. 이번 시간이 마지막 시간입니다. 클라이언트 프로그램의 GUI를 작업하도록 할 것입니다. 서버로 메시지를 전송하고, 서버로부터 메시지를 받는 전반적인 과정이 모두 그래픽 환경에서 출력될 것입니다. 클라이언트 프로그램 또한 프로그램 자체가 작고 디자인 구성요소가 별로 없다는 점에서 자바 소스코드로 간단하게 작성할 수 있을 것입니다.


  바로 클라이언트 프로그램을 실질적으로 작동시키는 start() 함수를 작업해보도록 하겠습니다.

 


  소스코드가 조금 긴 감이 있는데요. 클라이언트의 경우에는 UI 요소가 많기 때문에 어쩔 수 없습니다. 보시면 접속을 할 때 clientStart() 메소드를 실행해서 서버에 연결한 이후에 메시지를 전송하게 되면 서버로 send() 메소드를 이용해 통신하게 되는 것을 알 수 있습니다. 실행 결과는 다음과 같습니다.



  실제로 상용화를 위해서는 갖가지 예외 처리를 더욱 자세하게 해주어야 합니다. 일단 전반적인 작동이 원활히 이루어지는 것을 확인했으므로 프로젝트를 완료하겠습니다.

728x90
반응형

Comment +4

  • 자바사용자 2018.04.06 21:32

    정상적으로 작동이 잘 되네요!
    데스크탑에 서버,클라이언트 하나 노트북에 클라이언트 하나두고 해봤는 데 잘 됩니다!
    근데 jsp영상도 공부하려고 하는데 솔직히 웹개발에 이클립스는 별로이지 않나요????
    안경님이 능숙하게 사용하시는게 신기해보입니다..(코드도 매우 깔끔하게 짜시고)
    어쨋든 채팅강의 잘보았습니다. 좋은 하루되세요!

    • 이클립스가 전자정부 덕에 강세를 보인 것은 사실입니다. 사실 저는 그렇게 불편하다고 못느껴서 사용하고 있습니다. 정상적으로 잘 작동한다니 정말 다행이네요.

  • 홍길동 2018.07.10 09:48

    관리자의 승인을 기다리고 있는 댓글입니다

  • kdu 2019.10.01 17:56

    관리자의 승인을 기다리고 있는 댓글입니다

728x90
반응형

  이번 시간은 자바 FX(Java FX)를 이용한 서버 및 클라이언트 채팅 프로그램 개발하기의 네 번째 시간입니다. 바로 클라이언트 기능 모듈을 개발하는 것입니다. 일단 클라이언트 프로그램이라고 할 수 있는 Chat Client 프로젝트를 생성해주도록 합시다. 기본적으로 GUI 멀티 채팅 시스템에서 채팅 클라이언트(Chat Client) 프로그램은 서버로 접속하여 서버와 통신하는 구조를 가집니다. 바로 한 번 이클립스에서 JavaFX 프로젝트를 새롭게 생성하여 이름을 Chat Client라고 설정해줍시다. 서버 프로그램을 만들었을 때와 비슷하죠.



  바로 프로젝트를 생성해주겠습니다. JavaFX로요.



  위와 같이 이름을 Chat Client라고 설정해줍시다.



  이제 위와 같이 Main.java 클래스를 살펴보도록 합시다. 다음과 같이 틀을 잡아주세요.



  이제 바로 세부 메소드들을 작업해주도록 하겠습니다. 클라이언트 프로그램에서는 쓰레드 풀을 사용할 필요가 없기 때문에 기본적으로 Thread 클래스를 이용해서 쓰레드 모듈을 처리합니다.



  먼저 위와 같이 startClient() 메소드를 작업합니다. 클라이언트 프로그램을 동작하게 해주는 메소드입니다.



  이후에 서버로부터 메시지를 받거나 보내는 receive() 함수와 send() 함수를 작업해줍니다. 단순하게 InputStream과 OutputStream을 이용해서 서버와 통신하는 모듈이 작성된 것을 알 수 있습니다.



  이제 위와 같이 stopClient()를 작업해주시면 끝입니다.

728x90
반응형

Comment +2

728x90
반응형

  이번 시간에도 지난 시간에 이어서 자바 FX(Java FX)를 이용한 서버 및 클라이언트 채팅 프로그램을 개발하도록 합시다. 지난 시간에는 서버 프로그램의 서버 기능 모듈을 작업하는 시간을 가졌습니다. 이번 시간에는 실제로 GUI 환경에서 해당 서버가 작동하고 있는지의 여부를 출력하도록 해보겠습니다. 자바 FX도 다른 GUI 환경의 프로그램 도구와 흡사하게 작동합니다. 일반적으로 자바 FX는 FXML이라는 별도의 디자인 관련 소스코드를 사용하는데 특별한 GUI가 필요한 건 아니므로 소스코드 상으로 작업해보겠습니다.


  바로 실제로 서버 GUI를 작동시키는 start() 프로그램을 작업해보도록 할게요.



  위와 같이 작업하면 됩니다. 실행 결과는 다음과 같습니다.




728x90
반응형

Comment +3

728x90
반응형

  이번 시간은 자바 FX(Java FX)를 이용한 서버 및 클라이언트 채팅 프로그램 개발하기의 두 번째 시간입니다. 바로 서버 기능 모듈을 개발하는 것입니다. 일단 서버 프로그램이라고 할 수 있는 Chat Server 프로젝트를 생성해주도록 합시다. 기본적으로 GUI 멀티 채팅 시스템에서는 채팅 서버(Chat Server) 프로그램은 클라이언트(Client) 간의 중계자 역할을 수행합니다. 나아가 쓰레드 풀(Thread Pool)을 이용하기 위해서 Executer Service 라이브러리를 사용합니다.


  바로 이클립스에서 하나의 프로젝트를 생성해주도록 합시다.



  위와 같이 프로젝트 부분에서 마우스 우클릭 -> New -> Other에 들어갑니다.



  바로 위와 같이 JavaFX 프로젝트를 하나 생성해줍시다.



  프로젝트의 이름은 Chat Server라고 지어줄게요.

  


  처음에 프로젝트를 생성하면 바로 위와 같이 application 패키지가 존재하고 그 안에 Main 클래스가 존재할 겁니다.



  가장 먼저 위와 같이 application 패키지 내에 하나의 Client 라는 이름의 클래스를 생성해주겠습니다.



  이제 위와 같이 Main 클래스의 틀을 잡아보도록 합시다. 기본적으로 우리 프로젝트에서는 하나의 서버 프로그램은 오직 하나의 서버만 작동시킬 수 있도록 했습니다. 구현을 하고자 한다면 지난 시간에 보여드렸던 다이어그램처럼 하나의 서버 프로그램에서 여러 개의 서버 쓰레드를 작동시킬 수는 있지만 일반적으로는 하나의 서버 프로그램은 하나의 서버 모듈을 구동시킨다는 점에서 이렇게 개발하고자 합니다.


  간단히 부가설명을 하자면 ExecutorService는 여러 개의 쓰레드를 효율적으로 관리하기 위한 대표적인 라이브러리입니다. Thread Pool로 쓰레드를 처리하게 되면 기본적인 쓰레드 숫자의 제한을 두기 때문에 갑작스런 Client 폭증에도 쓰레드의 수에는 제한이 있어 서버의 성능 저하를 방지할 수 있습니다. 한정된 자원을 '안정적으로' 관리하기 위한 대비책이죠.


  바로 한 번 Client 클래스를 작성해보도록 합시다.


 먼저 바로 위와 같이 receive() 함수를 작성할 수 있습니다. 반복적으로 해당 클라이언트로부터 메시지를 전달 받는 메소드입니다. 소름 돋는 부분은 메시지를 전달 받자마자 곧바로 모든 클라이언트에게 그대로 전달해준다는 것입니다.



  이후에 send() 함수입니다. 특정한 클라이언트에게 특정 시기에 메시지를 전달하는 메소드입니다. 이제 특정한 클라이언트가 접속하게 되면 바로 위의 receive() 메소드와 send() 메소드를 이용해 메시지를 전달 받고 전달 할 수 있습니다.




  이제 위와 같이 serverStart() 함수를 작성합시다.



  마지막으로 stopServer() 메소드입니다. 이 메소드는 서버 작동 종료 이후에 전체 자원을 할당 해제해주는 메소드입니다. 사실 이 메소드의 작성 여부가 서버 프로그램의 품질에 큰 영향을 미친다고 할 수 있습니다. 자원 해제는 굉장히 중요합니다.

728x90
반응형

Comment +0

728x90
반응형

  이번에 진행해 볼 미니 프로젝트는 자바 FX(Java FX)를 이용한 서버 및 클라이언트 채팅 프로그램 개발하기입니다. 자바 FX로 개발 된 프로그램으로는 무엇이 있을까요? 바로 대표적인 것이 이클립스(Eclipse) 개발환경입니다. 우리가 흔히 자바 프로그래밍을 연습하기 위해 사용하는 개발 도구인 이클립스 또한 사실은 자바로 개발되었다는 거죠. 알 바 아니라고요? 바로 시작해보도록 하겠습니다.


  기본적으로 서버와 클라이언트를 포함하는 프로그램이 있다면, 응당 서버와 클라이언트는 서로 다른 컴퓨터 환경에서 작동을 한다고 보시면 됩니다. 실제로 프로그램을 구현한 이후에는 서버 프로그램은 실제 서버(Server)에서 작동시키고, 클라이언트는 해당 서버에 접속을 하는 식으로 개발을 해야 하는 겁니다.


  또한 하나의 서버 프로그램은 여러 개의 서버를 구동시킬 수 있습니다. 하나의 서버 단위마다 쓰레드를 이용해서 작동시킬 수 있습니다. 이 때는 연결을 받아야 하는 것이므로 특정한 포트 번호를 설정시켜줘야 할 것입니다. 이후에 특정한 서버로 클라이언트가 접속하면 어떻게 처리할 수 있을까요? 바로 다음과 같이 해당 서버 쓰레드에서 단위 쓰레드를 클라이언트의 갯수만큼 만들어주어 클라이언트가 접속할 때마다 쓰레드를 실행하여 작동시킬 수 있습니다.



  다만 여기에서 단순하게 쓰레드만 돌리면 상당히 프로그램이 위험한 상태에 처할 수 있습니다. 그래서 일반적으로 쓰레드 풀(Thread Pool) 기법을 사용하여 쓰레드를 관리할 수 있습니다. 다음 시간부터 제대로 개발을 해 볼 건데요. 전체적인 구성은 바로 위와 같습니다. 우리는 서버 프로그램과 클라이언트 프로그램을 모두 개발할 것입니다. 실제로 만약에 이 프로그램을 배포한다면 개발자의 컴퓨터에서는 서버 프로그램을 돌릴 수 있고 다른 컴퓨터에서는 클라이언트 프로그램을 돌리면 됩니다.


  필요한 개발 도구는 다음과 같습니다.


  ▶ 이클립스 개발 환경: http://www.eclipse.org/



  ▶ JavaFX Scene Builder: http://www.oracle.com/technetwork/java/javafxscenebuilder-1x-archive-2199384.html



  ▶ 이클립스 JavaFX 플러그 인


728x90
반응형

Comment +1

  • 혼자본다고생각 2021.09.05 21:19

    관리자의 승인을 기다리고 있는 댓글입니다

728x90
반응형

  이제 JSP로 강의평가(Lecture Evaluation) 웹 사이트 개발하기의 열 한 번째 포스팅을 합니다. 사실상 지난 시간에 모든 기능들이 다 구현이 되었어요. 이제는 기본적인 프로젝트 뼈대가 완성되었으므로 다양한 기능을 붙이거나, 보안적인 요소를 처리하는 것이 좋겠지요. 저는 이번 시간에서는 간단히 기초 시큐어 코딩 방법에 대해서 소개해드리려고 합니다. XSS를 방지하는 겁니다. XSS는 기본적으로 특정 사용자가 다른 사용자와 통신하는 과정에서 발생할 수 있는 해킹 방법입니다. 대표적으로는, 강의 평가 글 자체가 될 수 있습니다. 따라서 강의 평가 글을 출력할 때는 자바스크립트를 실행할 수 있는 문장을 모두 치환하면 됩니다.


  ▶ EvaluationDAO.java 내부의 write() 함수 수정하기


public int write(EvaluationDTO evaluationDTO) {

PreparedStatement pstmt = null;

try {

String SQL = "INSERT INTO EVALUATION VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0);";

pstmt = conn.prepareStatement(SQL);

pstmt.setString(1, evaluationDTO.getUserID().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(2, evaluationDTO.getLectureName().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(3, evaluationDTO.getProfessorName().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setInt(4, evaluationDTO.getLectureYear());

pstmt.setString(5, evaluationDTO.getSemesterDivide().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(6, evaluationDTO.getLectureDivide().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(7, evaluationDTO.getEvaluationTitle().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(8, evaluationDTO.getEvaluationContent().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(9, evaluationDTO.getTotalScore().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(10, evaluationDTO.getCreditScore().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(11, evaluationDTO.getComfortableScore().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

pstmt.setString(12, evaluationDTO.getLectureScore().replaceAll("<", "&lt;").replaceAll(">", " &gt;").replaceAll("\r\n", "<br>"));

return pstmt.executeUpdate();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if(pstmt != null) pstmt.close();

if(conn != null) conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

return -1;

}


  위와 같이 설정해주면 게시글이 등록될 때 모든 꺾쇠가 치환되므로 기본적으로 자바스크립트 구문을 삽입하기가 어려워진답니다. 이미 시중에 나와있는 라이브러리가 많긴 한데, 대충 위와 같이 처리해도 XSS 공격이 까다로워지므로 나쁘지 않습니다. 테스트 결과는 다음과 같습니다.




  ※ 전체 실행 결과 (동영상 결과물) ※



728x90
반응형

Comment +0

728x90
반응형

  이번 시간에는 JSP로 강의평가(Lecture Evaluation) 웹 사이트 개발하기의 열 번째 강의입니다. 지난 시간에는 특정한 강의를 검색할 수 있고, 페이징 처리를 하여 페이지를 넘기면서 여러 강의를 볼 수 있도록 기능을 구현하는 시간을 가졌습니다. 이번 시간에는 특정한 강의를 추천하고, 자신이 작성한 글에 한해서 글을 삭제하는 기능을 개발하고자 합니다. 바로 시작해봅시다. 가장 먼저 지난 번에 데이터베이스를 설계하는 시간에 작성했었던 LIKEY 테이블을 조금 바꿔주도록 하겠습니다. 바로 다음과 같이 ALTER 명령어를 이용해서 (회원 아이디, 평가 번호)로 PRIMARY KEY를 줍시다. 왜냐하면 한 명은 특정한 글에 단 한 번만 추천을 누를 수 있어야 하기 때문입니다.


  ▶ ALTER TABLE LIKEY ADD PRIMARY KEY (userID, evaluationID);



  이후에 바로 EvaluationDAO.java 파일을 수정하도록 하겠습니다. 이번 시간에 구현할 기능을 위해 몇 가지 데이터베이스 접근 함수가 필요하기 때문이에요.


public int like(String evaluationID) {

PreparedStatement pstmt = null;

try {

String SQL = "UPDATE EVALUATION SET likeCount = likeCount + 1 WHERE evaluationID = ?";

pstmt = conn.prepareStatement(SQL);

pstmt.setInt(1, Integer.parseInt(evaluationID));

return pstmt.executeUpdate();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if(pstmt != null) pstmt.close();

if(conn != null) conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

return -1;

}

public int delete(String evaluationID) {

PreparedStatement pstmt = null;

try {

String SQL = "DELETE FROM EVALUATION WHERE evaluationID = ?";

pstmt = conn.prepareStatement(SQL);

pstmt.setInt(1, Integer.parseInt(evaluationID));

return pstmt.executeUpdate();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if(pstmt != null) pstmt.close();

if(conn != null) conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

return -1;

}

public String getUserID(String evaluationID) {

PreparedStatement pstmt = null;

try {

String SQL = "SELECT userID FROM EVALUATION WHERE evaluationID = ?";

pstmt = conn.prepareStatement(SQL);

pstmt.setInt(1, Integer.parseInt(evaluationID));

rs = pstmt.executeQuery();

while(rs.next()) {

return rs.getString(1);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if(pstmt != null) pstmt.close();

if(conn != null) conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

return null;

}


  위와 같이 총 3개의 함수를 추가해줍시다. 차례대로 추천을 눌러서 특정한 글의 추천 갯수가 증가되는 함수, 특정한 강의 평가 글을 지우는 함수, 특정한 강의 평가 글을 작성한 사용자의 아이디를 구하는 함수입니다. 이제 다음과 같이 우리의 프로젝트를 구성합니다. likey 패키지를 생성해서 LikeyDTO.java, LikeyDAO.java를 생성합니다. 그리고 deleteAction.jsp 페이지와 likeAction.jsp 페이지를 생성합니다. 이 두 페이지는 강의 평가 글을 지우는 액션 페이지, 강의 평가에 추천을 누르는 액션 페이지입니다.



  ▶ LikeyDTO.java


package likey;


public class LikeyDTO {


String userID;

int evaluationID;

String userIP;

public String getUserID() {

return userID;

}

public void setUserID(String userID) {

this.userID = userID;

}

public int getEvaluationID() {

return evaluationID;

}

public void setEvaluationID(int evaluationID) {

this.evaluationID = evaluationID;

}

public String getUserIP() {

return userIP;

}

public void setUserIP(String userIP) {

this.userIP = userIP;

}

public LikeyDTO(String userID, int evaluationID, String userIP) {

this.userID = userID;

this.evaluationID = evaluationID;

this.userIP = userIP;

}


}


  ▶ LikeyDAO.java


package likey;


import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;


public class LikeyDAO {


private Connection conn;


public LikeyDAO() {

try {

String dbURL = "jdbc:mysql://localhost:3306/LectureEvaluation";

String dbID = "root";

String dbPassword = "root1234";

Class.forName("com.mysql.jdbc.Driver");

conn = DriverManager.getConnection(dbURL, dbID, dbPassword);

} catch (Exception e) {

e.printStackTrace();

}

}

public int like(String userID, String evaluationID, String userIP) {

String SQL = "INSERT INTO LIKEY VALUES (?, ?, ?)";

try {

PreparedStatement pstmt = conn.prepareStatement(SQL);

pstmt.setString(1, userID);

pstmt.setString(2, evaluationID);

pstmt.setString(3, userIP);

return pstmt.executeUpdate();

} catch (SQLException e) {

e.printStackTrace();

}

return -1; // 추천 중복 오류

}

}


  ▶ deleteAction.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ page import="user.UserDAO"%>

<%@ page import="evaluation.EvaluationDAO"%>

<%@ page import="likey.LikeyDTO"%>

<%@ page import="java.io.PrintWriter"%>

<%

String userID = null;

if(session.getAttribute("userID") != null) {

userID = (String) session.getAttribute("userID");

}

if(userID == null) {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('로그인을 해주세요.');");

script.println("location.href = 'userLogin.jsp'");

script.println("</script>");

script.close();

return;

}

request.setCharacterEncoding("UTF-8");

String evaluationID = null;

if(request.getParameter("evaluationID") != null) {

evaluationID = (String) request.getParameter("evaluationID");

}

EvaluationDAO evaluationDAO = new EvaluationDAO();

if(userID.equals(evaluationDAO.getUserID(evaluationID))) {

int result = new EvaluationDAO().delete(evaluationID);

if (result == 1) {

session.setAttribute("userID", userID);

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('삭제가 완료되었습니다.');");

script.println("location.href='index.jsp'");

script.println("</script>");

script.close();

return;

} else {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('데이터베이스 오류가 발생했습니다.');");

script.println("history.back();");

script.println("</script>");

script.close();

return;

}

} else {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('자신이 쓴 글만 삭제 가능합니다.');");

script.println("history.back();");

script.println("</script>");

script.close();

return;

}

%>


  ▶ likeAction.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ page import="user.UserDAO"%>

<%@ page import="evaluation.EvaluationDAO"%>

<%@ page import="likey.LikeyDAO"%>

<%@ page import="java.io.PrintWriter"%>

<%!

public static String getClientIP(HttpServletRequest request) {

    String ip = request.getHeader("X-FORWARDED-FOR"); 

    if (ip == null || ip.length() == 0) {

        ip = request.getHeader("Proxy-Client-IP");

    }

    if (ip == null || ip.length() == 0) {

        ip = request.getHeader("WL-Proxy-Client-IP");

    }

    if (ip == null || ip.length() == 0) {

        ip = request.getRemoteAddr() ;

    }

    return ip;

}

%>

<%

String userID = null;

if(session.getAttribute("userID") != null) {

userID = (String) session.getAttribute("userID");

}

if(userID == null) {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('로그인을 해주세요.');");

script.println("location.href = 'userLogin.jsp'");

script.println("</script>");

script.close();

return;

}

request.setCharacterEncoding("UTF-8");

String evaluationID = null;

if(request.getParameter("evaluationID") != null) {

evaluationID = (String) request.getParameter("evaluationID");

}

EvaluationDAO evaluationDAO = new EvaluationDAO();

LikeyDAO likeyDAO = new LikeyDAO();

int result = likeyDAO.like(userID, evaluationID, getClientIP(request));

if (result == 1) {

result = evaluationDAO.like(evaluationID);

if (result == 1) {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('추천이 완료되었습니다.');");

script.println("location.href='index.jsp'");

script.println("</script>");

script.close();

return;

} else {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('데이터베이스 오류가 발생했습니다.');");

script.println("history.back();");

script.println("</script>");

script.close();

return;

}

} else {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('이미 추천을 누른 글입니다.');");

script.println("history.back();");

script.println("</script>");

script.close();

return;

}

%>


  이제 한 번 테스트를 해보도록 합시다.







728x90
반응형

Comment +0

728x90
반응형

  이번 시간에는 JSP 강의평가(Lecture Evaluation) 웹 사이트 개발하기의 아홉 번째 시간입니다. 이번 시간에는 등록된 강의 평가 글을 실질적으로 출력하고, 검색할 수 있는 기능을 구현해보도록 하겠습니다.


  ▶ EvaluationDAO.java에 검색 함수 추가하기


public ArrayList<EvaluationDTO> getList(String lectureDivide, String searchType, String search, int pageNumber) {

if(lectureDivide.equals("전체")) {

lectureDivide = "";

}

ArrayList<EvaluationDTO> evaluationList = null;

PreparedStatement pstmt = null;

String SQL = "";

try {

if(searchType.equals("최신순")) {

SQL = "SELECT * FROM EVALUATION WHERE lectureDivide LIKE ? AND CONCAT(lectureName, professorName, evaluationTitle, evaluationContent) LIKE ? ORDER BY evaluationID DESC LIMIT " + pageNumber * 5 + ", " + pageNumber * 5 + 6;

} else if(searchType.equals("추천순")) {

SQL = "SELECT * FROM EVALUATION WHERE lectureDivide LIKE ? AND CONCAT(lectureName, professorName, evaluationTitle, evaluationContent) LIKE ? ORDER BY likeCount DESC LIMIT " + pageNumber * 5 + ", " + pageNumber * 5 + 6;

}

pstmt = conn.prepareStatement(SQL);

pstmt.setString(1, "%" + lectureDivide + "%");

pstmt.setString(2, "%" + search + "%");

rs = pstmt.executeQuery();

evaluationList = new ArrayList<EvaluationDTO>();

while(rs.next()) {

EvaluationDTO evaluation = new EvaluationDTO(

rs.getInt(1),

rs.getString(2),

rs.getString(3),

rs.getString(4),

rs.getInt(5),

rs.getString(6),

rs.getString(7),

rs.getString(8),

rs.getString(9),

rs.getString(10),

rs.getString(11),

rs.getString(12),

rs.getString(13),

rs.getInt(14)

);

evaluationList.add(evaluation);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if(rs != null) rs.close();

if(pstmt != null) pstmt.close();

if(conn != null) conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

return evaluationList;

}


    기본적으로 사용자가 '최신순', '추천순'으로 검색하는 쿼리에 따라서 정렬을 다르게 합니다. 이후에 한 페이지 당 5개씩 평가 글을 출력하도록 위와 같이 구성해보았습니다. 이제 다음과 같이 index.jsp를 수정합시다.


  ▶ index.jsp 수정하기


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ page import="java.io.PrintWriter"%>

<%@ page import="user.UserDAO"%>

<%@ page import="evaluation.EvaluationDAO"%>

<%@ page import="evaluation.EvaluationDTO"%>

<%@ page import="java.util.ArrayList"%>

<%@ page import="java.net.URLEncoder"%>

<!doctype html>

<html>

  <head>

    <title>강의평가 웹 사이트</title>

    <meta charset="utf-8">

    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- 부트스트랩 CSS 추가하기 -->

    <link rel="stylesheet" href="./css/bootstrap.min.css">

    <!-- 커스텀 CSS 추가하기 -->

    <link rel="stylesheet" href="./css/custom.css">

  </head>

  <body>

<%

request.setCharacterEncoding("UTF-8");

String lectureDivide = "전체";

String searchType = "최신순";

String search = "";

int pageNumber = 0;

if(request.getParameter("lectureDivide") != null) {

lectureDivide = request.getParameter("lectureDivide");

}

if(request.getParameter("searchType") != null) {

searchType = request.getParameter("searchType");

}

if(request.getParameter("search") != null) {

search = request.getParameter("search");

}

if(request.getParameter("pageNumber") != null) {

try {

pageNumber = Integer.parseInt(request.getParameter("pageNumber"));

} catch (Exception e) {

System.out.println("검색 페이지 번호 오류");

}

}

String userID = null;

if(session.getAttribute("userID") != null) {

userID = (String) session.getAttribute("userID");

}

if(userID == null) {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("alert('로그인을 해주세요.');");

script.println("location.href = 'userLogin.jsp'");

script.println("</script>");

script.close();

}

boolean emailChecked = new UserDAO().getUserEmailChecked(userID);

if(emailChecked == false) {

PrintWriter script = response.getWriter();

script.println("<script>");

script.println("location.href = 'emailSendConfirm.jsp'");

script.println("</script>");

script.close();

return;

}

%>

    <nav class="navbar navbar-expand-lg navbar-light bg-light">

      <a class="navbar-brand" href="index.jsp">강의평가 웹 사이트</a>

      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar">

        <span class="navbar-toggler-icon"></span>

      </button>

      <div class="collapse navbar-collapse" id="navbar">

        <ul class="navbar-nav mr-auto">

          <li class="nav-item active">

            <a class="nav-link" href="index.jsp">메인</a>

          </li>

          <li class="nav-item dropdown">

            <a class="nav-link dropdown-toggle" id="dropdown" data-toggle="dropdown">

              회원 관리

            </a>

            <div class="dropdown-menu" aria-labelledby="dropdown">

<%

if(userID == null) {

%>

              <a class="dropdown-item" href="userLogin.jsp">로그인</a>

              <a class="dropdown-item" href="userRegister.jsp">회원가입</a>

<%

} else {

%>

              <a class="dropdown-item" href="userLogout.jsp">로그아웃</a>

<%

}

%>

            </div>

          </li>

        </ul>

        <form action="./index.jsp" method="get" class="form-inline my-2 my-lg-0">

          <input type="text" name="search" class="form-control mr-sm-2" placeholder="내용을 입력하세요.">

          <button class="btn btn-outline-success my-2 my-sm-0" type="submit">검색</button>

        </form>

      </div>

    </nav>

    <div class="container">

      <form method="get" action="./index.jsp" class="form-inline mt-3">

        <select name="lectureDivide" class="form-control mx-1 mt-2">

          <option value="전체">전체</option>

          <option value="전공" <%if(lectureDivide.equals("전공")) out.println("selected");%>>전공</option>

          <option value="교양" <%if(lectureDivide.equals("교양")) out.println("selected");%>>교양</option>

          <option value="기타" <%if(lectureDivide.equals("기타")) out.println("selected");%>>기타</option>

        </select>

        <select name="searchType" class="form-control mx-1 mt-2">

          <option value="최신순">최신순</option>

          <option value="추천순" <%if(searchType.equals("추천순")) out.println("selected");%>>추천순</option>

        </select>

        <input type="text" name="search" class="form-control mx-1 mt-2" value="<%= search %>" placeholder="내용을 입력하세요.">

        <button type="submit" class="btn btn-primary mx-1 mt-2">검색</button>

        <a class="btn btn-primary mx-1 mt-2" data-toggle="modal" href="#registerModal">등록하기</a>

        <a class="btn btn-danger ml-1 mt-2" data-toggle="modal" href="#reportModal">신고</a>

      </form>

<%

ArrayList<EvaluationDTO> evaluationList = new ArrayList<EvaluationDTO>();

evaluationList = new EvaluationDAO().getList(lectureDivide, searchType, search, pageNumber);

if(evaluationList != null)

for(int i = 0; i < evaluationList.size(); i++) {

if(i == 5) break;

EvaluationDTO evaluation = evaluationList.get(i);

%>

      <div class="card bg-light mt-3">

        <div class="card-header bg-light">

          <div class="row">

            <div class="col-8 text-left"><%=evaluation.getLectureName()%>&nbsp;<small><%=evaluation.getProfessorName()%></small></div>

            <div class="col-4 text-right">

              종합 <span style="color: red;"><%=evaluation.getTotalScore()%></span>

            </div>

          </div>

        </div>

        <div class="card-body">

          <h5 class="card-title">

            <%=evaluation.getEvaluationTitle()%>&nbsp;<small>(<%=evaluation.getLectureYear()%>년 <%=evaluation.getSemesterDivide()%>)</small>

          </h5>

          <p class="card-text"><%=evaluation.getEvaluationContent()%></p>

          <div class="row">

            <div class="col-9 text-left">

              성적 <span style="color: red;"><%=evaluation.getCreditScore()%></span>

              널널 <span style="color: red;"><%=evaluation.getComfortableScore()%></span>

              강의 <span style="color: red;"><%=evaluation.getLectureScore()%></span>

              <span style="color: green;">(추천: <%=evaluation.getLikeCount()%>)</span>

            </div>

            <div class="col-3 text-right">

              <a onclick="return confirm('추천하시겠습니까?')" href="./likeAction.jsp?evaluationID=<%=evaluation.getEvaluationID()%>">추천</a>

              <a onclick="return confirm('삭제하시겠습니까?')" href="./deleteAction.jsp?evaluationID=<%=evaluation.getEvaluationID()%>">삭제</a>

            </div>

          </div>

        </div>

      </div>

<%

}

%>

    </div>

    <ul class="pagination justify-content-center mt-3">

      <li class="page-item">

<%

if(pageNumber <= 0) {

%>     

        <a class="page-link disabled">이전</a>

<%

} else {

%>

<a class="page-link" href="./index.jsp?lectureDivide=<%=URLEncoder.encode(lectureDivide, "UTF-8")%>&searchType=<%=URLEncoder.encode(searchType, "UTF-8")%>&search=<%=URLEncoder.encode(search, "UTF-8")%>&pageNumber=<%=pageNumber - 1%>">이전</a>

<%

}

%>

      </li>

      <li class="page-item">

<%

if(evaluationList.size() < 6) {

%>     

        <a class="page-link disabled">다음</a>

<%

} else {

%>

<a class="page-link" href="./index.jsp?lectureDivide=<%=URLEncoder.encode(lectureDivide, "UTF-8")%>&searchType=<%=URLEncoder.encode(searchType, "UTF-8")%>&search=<%=URLEncoder.encode(search, "UTF-8")%>&pageNumber=<%=pageNumber + 1%>">다음</a>

<%

}

%>

      </li>

    </ul>

    <div class="modal fade" id="registerModal" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">

      <div class="modal-dialog">

        <div class="modal-content">

          <div class="modal-header">

            <h5 class="modal-title" id="modal">평가 등록</h5>

            <button type="button" class="close" data-dismiss="modal" aria-label="Close">

              <span aria-hidden="true">&times;</span>

            </button>

          </div>

          <div class="modal-body">

            <form action="./evaluationRegisterAction.jsp" method="post">

              <div class="form-row">

                <div class="form-group col-sm-6">

                  <label>강의명</label>

                  <input type="text" name="lectureName" class="form-control" maxlength="20">

                </div>

                <div class="form-group col-sm-6">

                  <label>교수명</label>

                  <input type="text" name="professorName" class="form-control" maxlength="20">

                </div>

              </div>

              <div class="form-row">

                <div class="form-group col-sm-4">

                  <label>수강 년도</label>

                  <select name="lectureYear" class="form-control">

                    <option value="2011">2011</option>

                    <option value="2012">2012</option>

                    <option value="2013">2013</option>

                    <option value="2014">2014</option>

                    <option value="2015">2015</option>

                    <option value="2016">2016</option>

                    <option value="2017">2017</option>

                    <option value="2018" selected>2018</option>

                    <option value="2019">2019</option>

                    <option value="2020">2020</option>

                    <option value="2021">2021</option>

                    <option value="2022">2022</option>

                    <option value="2023">2023</option>

                  </select>

                </div>

                <div class="form-group col-sm-4">

                  <label>수강 학기</label>

                  <select name="semesterDivide" class="form-control">

                    <option name="1학기" selected>1학기</option>

                    <option name="여름학기">여름학기</option>

                    <option name="2학기">2학기</option>

                    <option name="겨울학기">겨울학기</option>

                  </select>

                </div>

                <div class="form-group col-sm-4">

                  <label>강의 구분</label>

                  <select name="lectureDivide" class="form-control">

                    <option name="전공" selected>전공</option>

                    <option name="교양">교양</option>

                    <option name="기타">기타</option>

                  </select>

                </div>

              </div>

              <div class="form-group">

                <label>제목</label>

                <input type="text" name="evaluationTitle" class="form-control" maxlength="20">

              </div>

              <div class="form-group">

                <label>내용</label>

                <textarea type="text" name="evaluationContent" class="form-control" maxlength="2048" style="height: 180px;"></textarea>

              </div>

              <div class="form-row">

                <div class="form-group col-sm-3">

                  <label>종합</label>

                  <select name="totalScore" class="form-control">

                    <option value="A" selected>A</option>

                    <option value="B">B</option>

                    <option value="C">C</option>

                    <option value="D">D</option>

                    <option value="F">F</option>

                  </select>

                </div>

                <div class="form-group col-sm-3">

                  <label>성적</label>

                  <select name="creditScore" class="form-control">

                    <option value="A" selected>A</option>

                    <option value="B">B</option>

                    <option value="C">C</option>

                    <option value="D">D</option>

                    <option value="F">F</option>

                  </select>

                </div>

                <div class="form-group col-sm-3">

                  <label>널널</label>

                  <select name="comfortableScore" class="form-control">

                    <option value="A" selected>A</option>

                    <option value="B">B</option>

                    <option value="C">C</option>

                    <option value="D">D</option>

                    <option value="F">F</option>

                  </select>

                </div>

                <div class="form-group col-sm-3">

                  <label>강의</label>

                  <select name="lectureScore" class="form-control">

                    <option value="A" selected>A</option>

                    <option value="B">B</option>

                    <option value="C">C</option>

                    <option value="D">D</option>

                    <option value="F">F</option>

                  </select>

                </div>

              </div>

              <div class="modal-footer">

                <button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button>

                <button type="submit" class="btn btn-primary">등록하기</button>

              </div>

            </form>

          </div>

        </div>

      </div>

    </div>

    <div class="modal fade" id="reportModal" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">

      <div class="modal-dialog">

        <div class="modal-content">

          <div class="modal-header">

            <h5 class="modal-title" id="modal">신고하기</h5>

            <button type="button" class="close" data-dismiss="modal" aria-label="Close">

              <span aria-hidden="true">&times;</span>

            </button>

          </div>

          <div class="modal-body">

            <form method="post" action="./reportAction.jsp">

              <div class="form-group">

                <label>신고 제목</label>

                <input type="text" name="reportTitle" class="form-control" maxlength="20">

              </div>

              <div class="form-group">

                <label>신고 내용</label>

                <textarea type="text" name="reportContent" class="form-control" maxlength="2048" style="height: 180px;"></textarea>

              </div>

              <div class="modal-footer">

                <button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button>

                <button type="submit" class="btn btn-danger">신고하기</button>

              </div>

            </form>

          </div>

        </div>

      </div>

    </div>

    <footer class="bg-dark mt-4 p-5 text-center" style="color: #FFFFFF;">

      Copyright ⓒ 2018 나동빈 All Rights Reserved.

    </footer>

    <!-- 제이쿼리 자바스크립트 추가하기 -->

    <script src="./js/jquery.min.js"></script>

    <!-- Popper 자바스크립트 추가하기 -->

    <script src="./js/popper.min.js"></script>

    <!-- 부트스트랩 자바스크립트 추가하기 -->

    <script src="./js/bootstrap.min.js"></script>

  </body>

</html>


  이제 한 번 실행해서 테스트를 해보도록 하겠습니다.






728x90
반응형

Comment +4

  • 안경벗은개발자 2018.03.28 14:40

    위에 올려놓은 소스에 문제가 있습니다.

    1. textarea 는 type으로 text를 따로 명시하면 안됩니다.
    2. option은 value로 지정해야합니다. name으로 주면 안됩니다.
    3. connection에 대해 초기화 해주지않았습니다.
    4. connection conn에 util패키지 하위에 getConnection을 해줘야 합니다.

    • 제가 몰랐던 내용을 말씀해주셔서 감사합니다! 글은 수정이 가능한데, 유튜브에 올려 놓은 동영상 강좌는 수정이 불가능해 마음이 아프네요...

    • 안경벗은개발자 2018.04.17 09:59

      항상 응원합니다.
      유투브등으로 많은 도움이되어,
      그간의 지식에 대한 보상으로 유데미 유료결제또한 해드렸구요.
      학업으로 많이 바쁘신거같군요..
      아직 메세지 응답이나, 메일을 확인하지 못하는듯 한데.. 힘내세요

  • ji 2019.12.03 23:19

    관리자의 승인을 기다리고 있는 댓글입니다