2018년 4월 30일 월요일

MySQL의 외부 IP 접속 허용하기





MySQL의 외부 IP 접속 허용하기

Java에서 MySQL을 접속할 때 localhost로 접속하거나 127.0.0.1로 접속할 때는 정상적으로 잘 되던 것이 

String url = "jdbc:mysql://192.168.x.x:3306/mysql";

장비의 실제 IP주소나 도메인 이름으로 접속할때 다음과 같은 에러가 발생할 때 

javax.servlet.ServletException: java.sql.SQLException: null,  message from server: "Host 'xxxx' is not allowed to connect to this MySQL server"

이 경우는 MySQL을 외부에서 접속할 수 있도록 권한을 허용해 주어야 한다.

mysql -uroot -p
Enter password:

로 접속해서 다음 과정으로 외부 IP에서 접속할 수 있도록 권한을 허용해 주어야 한다.

mysql> use mysql;
Database changed
mysql>

다음 명령을 실행해 보면 MySQL에 접속할 수 있는 user들의 계정과 접속이 가능한 host가 다음과 같이 나타날 것이다.

mysql> select host, user from user;
+-----------+------+
| host         | user |
+-----------+------+
| 127.0.0.1   | root |
| ::1           | root |
| localhost   |      |
| localhost   | root |
+-----------+------+
4 rows in set (0.00 sec)

위에서 보는 바와 같이 접속이 가능한 host가 localhost와 127.0.0.1에 대해서만 root id로 접속이 가능하다.  따라서 다음코드는 정상적으로 접속이 가능하다.
String url = "jdbc:mysql://localhost:3306/mysql";
String url = "jdbc:mysql://127.0.0.1:3306/mysql";

그러나 만일 MySQL이 설치된 컴퓨터의 IP가 만일 192.168.122.19라고 한다면 다음과 같은 코드는 "Host 'xxxx' is not allowed to connect to this MySQL server"과 같은 에러가 발생한다.

String url = "jdbc:mysql://192.168.122.19:3306/mysql";

다음 명령어로 외부 접속 권한을 설정한다.
mysql> GRANT ALL PRIVILEGES ON DB명.* TO 사용자계정@'IP주소' identified by 'password';
예) mysql> grant all privileges on mysql.* to 'root'@'%' identified by 'xxxxx';

위에서 IP주소 부분을 %로 지정하면 모든 외부의 IP를 모두 허용한다는 뜻이다.

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

이후부터는 외부 IP에서의 접속이 정상적으로 실행된다.

mysql> select host, user from user;
+-----------+------+
| host        | user |
+-----------+------+
| %           | root |
| 127.0.0.1  | root |
| ::1           | root |
| localhost  |      |
| localhost  | root |
+-----------+------+
5 rows in set (0.00 sec)

위에서 보는 바와 같이 host가 %로 모든 IP에서의 접속이 가능하도록 설정되어 있음을 확인할수 있다.



JSP(Java)에서 MySQL 연동하기





JSP(Java)에서 MySQL 연동하기

Java에서 MySQL 연동하는 코드 자체는 단순하고 간단하다. 
 ① 연동을 위해 필요한 2개의 클래스 : Connection, DriverManager
 ② 필요한 클래스를 import 한다.
    <%@page import="java.sql.DriverManager"%>
    <%@page import="java.sql.Connection"%>
 ③ 연동을 위해 필요한 .jar 라이브러리(mysql-connector-java-5.1.40-bin.jar)를 톰캣이 설치된 디렉토리의 lib 폴더에 복사해 둔다. 혹은 해당 프로젝트의 \WebContent\WEB-INF\lib 아래에 복사해 둔다.
     예) D:\apache-tomcat-7.0.69\lib에 복사해 둔다.

코드는 아래와 같다.

<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<%
Connection conn = null;
      
                //localhost는 MySQL이 설치된 곳의 IP
                //mysql : DB 명
                //3306 : MySQL 접속을 위한 디폴트 포트
String url = "jdbc:mysql://localhost:3306/mysql";
String id = "root";                     //MySQL에 접속을 위한 계정의 ID
String pwd = "xxxxxxx";            //MySQL에 접속을 위한 계정의 암호
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, id, pwd);
out.println("<h1>MySQL DB 연결 성공</h1>");
%>
</body>
</html>

실행 중에 만일 아래와 같은 에러가 발생한다면 이 문제는 위 ③을 하지 않음으로 인한 문제이다. ③과정을 처리하면 된다.

org.apache.jasper.JasperException: An exception occurred processing JSP page /connect.jsp at line 19

18: 
19:  Class.forName("com.mysql.jdbc.Driver");
20:  conn = DriverManager.getConnection(url, id, pwd);
21: 

... 중 략 ...

javax.servlet.ServletException: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

위의 코드는 로컬 상에서(JSP가 구동되는 곳과 MySQL이 설치된 곳이 동일 컴퓨터일 경우)의 MySQL 연동하는 법이다.
그런데 개발을 할때 원격의 서버에 있는 MySQL과 연동하면서 개발하는 경우가 있다. 이때는 아래 코드를 

String url = "jdbc:mysql://localhost:3306/mysql";

다음과 같이 IP 주소 혹은 도메인 이름으로 접속해야 한다.
String url = "jdbc:mysql://192.168.x.x:3306/mysql";

이렇게 MySQL에 접속을 시도했을 때 다음과 같은 에러가 발생한다면 

org.apache.jasper.JasperException: An exception occurred processing JSP page /connect.jsp at line 21

19: 
20:  Class.forName("com.mysql.jdbc.Driver");
21:  conn = DriverManager.getConnection(url, id, pwd);
22: 

...중 략...

javax.servlet.ServletException: java.sql.SQLException: null,  message from server: "Host 'xxxx' is not allowed to connect to this MySQL server"

이 에러는 MySQL이 외부 접속을 허용하지 않음으로 인한 에러이다.
이 문제에 대한 해법은 아래 링크 참조


2018년 4월 25일 수요일

Servlet에서 초기화 파라미터 사용하기





JSP/Servlet을 이용하여 웹 프로그램을 개발하다보면 DB를 사용하는 일은 통상적으로 있는 일이다. DB의 성격상 보안이 잘 유지되어야 할텐데 이때 Java 소스 코드 안에 DB 접속 정보를 그대로 코딩하는 경우가 있다. 이는 보안상 결코 바람직 하지 않은 일이다.
물론 Java(Servlet)을 컴파일한 class 파일만 서버에 올리면 일단 해당 정보가 막바로 보이지는 않겠지만 좀더 보안을 생각한다면 Servlet의 초기화 파라미터를 이용하는 것이 더 좋은 방법일 것이다.
Servlet 초기화 파라미터는 모든 Servlet에서 사용할수 있는 것이 아니라 특정 Servlet에 국한되어 사용하는 경우이다. 
해당 프로젝트의 web.xml 안에 해당 Servlet이 생성될 때 사용할 데이터들을 작성해 두면 된다. 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>ExServlet</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
   <servlet-name>OhServlet</servlet-name>
   <servlet-class>com.joe.myservlet.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
   <servlet-name>OhServlet</servlet-name>
   <url-pattern>/OhSRLT</url-pattern>
  </servlet-mapping>
</web-app>

이때 초기화 파라미터를 작성하는 위치는 이 초기화 데이터를 사용할 Servlet의 태그 안에 작성해야 한다. 이 경우에는 com.joe.myservlet.HelloServlet에서 초기화 데이터를 사용하고자 한다고 가정하면 아래와 같이 작성을 하면 된다.

  <servlet>
   <servlet-name>OhServlet</servlet-name>
   <servlet-class>com.joe.myservlet.HelloServlet</servlet-class>
   <init-param>
   <param-name>myDB</param-name>
   <param-value>jdbc:mysql://①:3306/②?autoReconnect=true</param-value>
   </init-param>
   <init-param>
   <param-name>dbUser</param-name>
   <param-value>hisUser</param-value>
   </init-param>
   <init-param>
   <param-name>dbPW</param-name>
   <param-value>qwerty1</param-value>
   </init-param>
  </servlet>
  <servlet-mapping>
   <servlet-name>OhServlet</servlet-name>
   <url-pattern>/OhSRLT</url-pattern>
  </servlet-mapping>

여기에서 위 ①에는 MySQL이 설치되어 있는 서버의 IP 주속 혹은 도메인 이름을, ②에는 사용할 Database 이름을 명기하면된다.
다음과 같은 형태가 될 것이다.

<param-value>jdbc:mysql://118.277.xxx.x:3306/theDB?autoReconnect=true</param-value>
혹은
<param-value>jdbc:mysql://myblog.or.kr:3306/theDB?autoReconnect=true</param-value>

그러면 이렇게 작성된 초기화 값을 Servlet에서 사용할려면 ServletConfig 인터페이스의 getInitParameter() 메소드를 이용해서 초기화 파라미터의 값을 가져올수 있다.
ServletConfig 인터페이스에 대한 Oralce의 API 문서에는 다음과 같이 설명되어 있다.

public interface ServletConfig
A servlet configuration object used by a servlet container to pass information to a servlet during initialization.

All Known Implementing Classes:
GenericServlet, HttpServlet

package com.joe.myservlet;

public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
       
... 중 략 ...

private void doAction(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException 
{

... 중 략 ...
//아래에서 getInitParameter() 메소드를 막바로 사용할수 있는 이유는 본 클래스가 HttpServlet을 
//상속받았는데 HttpServlet이 ServletConfig라는 interface을 implement했기 때문이다.
//즉 getInitParameter()는 ServletConfig 인터페이스의 메소드인데 HttpServlet이
//이 ServletConfig를 구현했기 때문에 아래에서 막바로 사용가능한 것이다.
String db = getInitParameter("myDB");
String dbUser = getInitParameter("dbUser");
String dbPw = getInitParameter("dbPW");
... 중 략 ...
     PrintWriter out = response.getWriter();
out.println("<hr/>");
out.println("db : " + db+"<br/>");
out.println("user : " + dbUser+"<br/>");
out.println("dbPassword : " + dbPw+"<br/>");
out.close();
}

2018년 4월 24일 화요일

FullStack 웹 개발자가 갖추어야 할 기술들에 대해





Fullstack 웹 개발자가 갖추어야 할 기술들에 대해 간략하게 잘 정리되어 있는 사이트이다.

https://medium.com/codingthesmartway-com-blog/the-2018-roadmap-to-fullstack-web-development-8884ff02557a

VirtualBox의 Linux 가상 머신의 저장 장소를 다른 드라이브로 옮기기





VirtualBox에 리눅스를 가상 머신 형태로 사용하다보면 HDD의 공간을 많이 차지하게 되고 여러가지 프로그램들을 설치하다보면 공간의 압박에 시달리게 된다. 
따라서 이로인해 C:에 있던 리눅스 가상 머신을 D: 드라이브로 옮겨야 할 필요가 발생하게 된다.
이에 대해 아래 사이트에서 정확한 방법을 소개하고 있다.

https://www.techrepublic.com/article/how-to-move-virtualbox-vms-from-one-drive-to-another/

2018년 4월 23일 월요일

meta 태그를 이용해서 일정 시간 경과하면 특정 웹 페이지로 자동 이동하기





meta 태그를 이용해서 일정 시간 경과하면 특정 웹 페이지로 자동 이동하기

아래 코드는 3초 후에 같은 경로상의 MyJsp.jsp로 이동한다.

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Insert title here</title>
<meta http-equiv="Refresh" content="3;url=./MyJsp.jsp">
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<style type="text/css">
.joe {color:Green; font-size:30pt;}
</style>
</head>
<body>
<span class="joe">This is Test</span>
<p/>
<input type="text" size="10" value=<%out.println("방가 방가"); %>>
</body>
</html>

만일 네이버로 이동하고 싶다면 아래와 같이 http를 붙여서 다음과 같이 수정한다.
<meta http-equiv="Refresh" content="3;url=http://www.naver.com">

만일 다른 페이지로의 이동 없이 현재 페이지를 1문마다 자동으로 새로 고침할려면 다음과 같이 이동 url없이
<meta http-equiv="Refresh" content="60">

JSP에서 EL(Expression Language)이 값을 출력하지 못할 경우





JSP에서 EL(Expression Language)이 값을 출력하지 못할 경우

JSP에서 EL을 사용하여 값을 출력하고자 할때 다음 코드에서 str1의 값 "Hello world~~~"이 정상적으로 출력이 될까?

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<jsp:useBean id="member" class="com.joe.test.MemberInfo" scope="page"/>
<jsp:setProperty name="member" property="id" value="abcde" />
<jsp:setProperty name="member" property="pwd" value="kog" />
<jsp:setProperty name="member" property="name" value="고길동" />    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>EL 사용시 주의 사항</title>
</head>
<body>
<%
String str1 = "Hello world~~~";
%>
아이디 : <jsp:getProperty name="member" property="id"/><br/>
비밀번호 : <jsp:getProperty name="member" property="pwd"/><br/>
이름 : <jsp:getProperty name="member" property="name"/><br/>
<hr/>
아이디 : ${member.id }<br/>
비밀번호 : ${member.pwd }<br/>
이름 : ${member.name }<br/>
<hr/>
str1 : ${str1 }<br/>
</body>
</html>

정답은 출력되지 않는다이다.  출력 결과는 다음과 같다.

아이디 : abcde
비밀번호 : kog
이름 : 고길동
아이디 : abcde
비밀번호 : kog
이름 : 고길동
str1 : 

str1에는 아무것도 출력되지 않는다. 이유가 뭘까? 저 값이 출력되게 할려면 어떻게 해야 할까?
관건은 EL에서 사용할수 있는 변수의 범위(scope)와 관련된 문제이다. 즉 EL 태그가 값을 참조할수 있는 가용 영역(범위, scope)의 문제 때문이다.
EL 태그가 값을 가져올수 있는 영역은 pageContext 영역에 있는 변수의 값, request 영역에 있는 값, session 영역에 있는 값, application 영역에 있는 값이다.
따라서 위의 코드를 다음과 같이 수정하면 Hello world~~~라는 문자열이 정상적으로 출력이 된다.

<%
String str1 = "Hello world~~~";
    
  //다음 4개 중 어느 하나를 추가하면 str1의 값을 EL에서 정상적으로 출력가능하다.
pageContext.setAttribute("str1", str1);
//request.setAttribute("str1", str1);
//session.setAttribute("str1", str1);
//application.setAttribute("str1", str1);
%>

이때 str1의 값을 현재 페이지에서만 사용하면 되는 상황이라면 pageContext, request 영역에 str1의 값을 저장하면 될 것이다(pageContext.setAttribute() 혹은 request.setAttribute() 사용).
만일 좀 더 넓은 범위에서 사용이 필요하다면 session 영역에 저장하면 될 것이다. 
혹은 웹 애플리케이션 전 영역에서 서버 가동 동안 계속 사용이 필요하다면 application 영역에 값을 저장하면 될 것이다(application.setAttribute() 사용).

혹은 JSTL을 사용하여 

<%
     String str1 = "Hello world~~~";
%>
대신에 다음과 같이 JSTL 태그를 사용하면 pageContext, request, session.... 등 사용 없이 EL에서 정상적으로 값을 참조가능 하다.

<%
    <c:set var="str1" value="Hellow world~~~" />
%>

같은 개념으로 다음 코드는 어떻게 될까?

<%
    String myId = (String)request.getAttribute("id");
    String mAtt = (String)request.getAttribute("ctrlAttr");
%>

(1) 컨트롤럴에서 넘어온 값(myId) : ${myId}<br/>
(2) 컨트롤럴에서 넘어온 값(id) : ${id}<br/>
(3) 컨트롤럴에서 넘어온 값(mAtt) : ${mAtt}<br/>
(4) 컨트롤럴에서 넘어온 값(ctrlAttr) : ${ctrlAttr}<br/>

결과는 (1)(3)은 아무 값도 출력되지 않는다.
반면에 (2)(4)은 정상적으로 값이 출력이 된다.
이 경우는 request 영역에 이미 값이 저장되어 있으므로 저장된 값을 가져오기 위한 key 값인 id, ctrlAttr을 막바로 사용하면된다. 

만일 다음과 같이 parameter 형태로 넘어올 경우 EL에서 값을 참조하는 방법은 다음과 같다.

<jsp:forward page="toPage.jsp">
<jsp:param name="mUrl" value="www.naver.com"/>
<jsp:param name="mUser" value="고길동"/>
</jsp:forward>

이 경우 toPage.jsp에서 다음과 같이 파라미터로 넘어오는 값을 받을 수 있다.

<body>
<%
String tUrl = request.getParameter("mUrl");
String tUser = request.getParameter("mUser");
%>

<h1>여기는 toPage.jsp입니다.</h1>
<ul>
<li>url : <%=tUrl %></li>  <!-- 정상적으로 값이 출력된다 -->
<li>user : <%=tUser %></li>
</ul>
<hr/>
<ul>
<li>*url => ${mUrl }</li> <!-- 이런식으로는 값을 참조할 수 없다. -->
<li>*user => ${mUser }</li>
</ul>

<hr/>
<ol>
<li>URL : ${param.mUrl }</li>  <!-- 정상적으로 값이 출력된다 -->
<li>USER : ${param.mUser }</li>
</ol>

</body>

2018년 4월 19일 목요일

이클립스 프로젝트의 오류 표시(빨간 색 x박스) 문제





다른 PC에서 개발하던 (프로젝트들이 담겨 있는) 워크 스페이스를 통채로 복사해 와서 이클립스로 열었더니 아래 그림과 같이 프로젝트들 이름마다 빨간 색 엑스박스가 떴다. 이클립스에서의 이 문제는 흔히 만나는 문제이다.



이럴 경우는 대부분 이전 PC에서의 JDK, Tomcat 등의 개발 환경 설정과 현재 PC에서의 개발환경 설정이 달라서 생기는 문제이다.
즉 JDK, Tomcat 등의 클래스 패스가 잘못됨 때문이다.

해당 프로젝트에서 마우스 우 클릭 ⇒ 팝업 메뉴의 Build Path ⇒ Configure Build Path... ⇒ Libraries 탭으로 이동한다.



아래 이미지에서 보는 것 처럼 JRE의 클래스 패스가 잘못되었다고 빨간색 엑스박스가 표시되어 있다. 해당 항목을 클릭하면 우측에 Remove 버튼이 활성화되고 이 버튼을 클릭해서 해당 항목을 삭제한다.



그 후에 Add Library... 버튼을 클릭한다. 그 후에 JRE System Library를 선택 후 Next 버튼으로 넘어간다.



아래 그림과 같이 현재 PC에 설치되어 있는 JRE를 선택한다. 디폴트가 잡혀있지 않다면 우측의 Installed JREs... 버튼을 클릭해서 현재 PC에 설치된 JRE를 선택한다. Finish 버튼을 눌러 완료한다.



만일에 아래 그림과 같이 Java Build Path에 톰캣 라이브러리가 없는 경우가 있다.


이때도 우측의 Add Library... 버튼 클릭. Add Library 창에서 이번에는 Server Runtime 항목을 선택 후 Next 버튼. 새로운 창에서 현재 PC에 설치되어 있는 Apache Tomcat v7.0을 선택 후 Finish.

이렇게 하면 외부 개발환경과 다른 문제로 인해 발생하는 문제들을 해결할수 있다.