1. Sqlite DB 테이블 생성하고 CSS 파일 만들기

CSS는 src > main > webapp > resources 아래에 넣는다.

 

2. 기본 폼

HomeController.java

package com.KOPO.Users;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		
		return "home";
	}
	
	@RequestMapping(value = "/signup", method = RequestMethod.GET)
	public String signup(Locale locale, Model model) {

		return "signup";
	}
	
	@RequestMapping(value = "/signin", method = RequestMethod.GET)
	public String signin(Locale locale, Model model) {

		return "signin";
	}
}

 

DataReader.java

package com.KOPO.Users;

import java.sql.Connection;
import java.sql.DriverManager;
import org.sqlite.SQLiteConfig;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;

public class DataReader {
	private Connection connection;
	private String dbfileName;
	private String dbTableName;
	static {
		try {
			Class.forName("org.sqlite.JDBC");
			
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	public DataReader(String databaseFileName, String dbTableName) {
		this.dbfileName = databaseFileName;
		this.dbTableName = dbTableName;
	}
	public boolean open() {
		try {
			SQLiteConfig config = new SQLiteConfig();
			this.connection = DriverManager.getConnection("jdbc:sqlite:/" + 
			this.dbfileName, config.toProperties());
		}catch(SQLException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public boolean close() {
		if(this.connection == null) {
			return true;
		}
		try { 
			this.connection.close();
			
		}catch(SQLException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

}

 

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
	<head>
		<title>Home</title>
	</head>
	<body>
		<h1>
			User Data
		</h1>
		<a href="/Users/private">개인정보</a><br />
		<a href="/Users/signin">로그인</a>&nbsp;&nbsp;<a href="/Users/signout">로그아웃</a>&nbsp;&nbsp;<a href="/Users/signup">회원가입</a><br/><br/>
	</body>
</html>

 

위 기본 폼에 명령을 추가하고(HomeController), SQL을 만들고(DataReader), 페이지를 만든다(.jsp)

 

3. 기능 만들기 (C : Insert)

계정을 만들어보자.

1. View를 수정하자.(signup.jsp)

HTML 코드 부분은 atom에서 작성해서 STS에 복붙한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/sign_up.css">
		<title>회원가입</title>
	</head>
	<body>
		<h1>회원가입</h1>
		<a href="/Users/">홈으로</a><br /><br />
		
		<!-- form 태그는 type="submit" 버튼을 누르면 action을 실행한다. name은 각각 파라미터 이름이 되고, 입력된 값은 각 파라미터의 값이 된다. HomeController에서 HttpServletRequest가 .getParameter를 통해 파라미터와 값에 접근한다. -->
	 	<form action="/Users/signup_action" method = "post">
	 		이름 <input type="text" name="name" placeholder="이름을 입력해주세요" />
		    <br />
		    ID <input type="text" name="id" placeholder="아이디를 입력해주세요" />
		    <br />
		    PW <input type="password" name="password" placeholder="패스워드를 입력해주세요" />
		    <br /><br />
	    	<input type="submit" name="" value="회원가입" />
	 	</form>
	 	
	</body>
</html>

 

2. DB와 통신하는 Model를 수정하자.(DataReader.java)

	// signupAction에 대한 Insert 쿼리를 날려주는 메소드를 생성한다.
	public int insertData(String name, String id, String password) throws SQLException {
		String query = "INSERT INTO " + this.dbTableName + " (name, id, password) VALUES('" + name + "', '" + id + "', '" + password + "');";
		Statement statement = this.connection.createStatement();	// Statement를 이용해 접속 엔진을 연다.
		int result = statement.executeUpdate();	// 엔진을 이용해 쿼리를 보낸다.
		statement.close();		// 접속 엔진을 닫는다.
		
		return result;
	}

String query = "INSERT INTO " + this.dbTableName + " (name, id, password) VALUES('" + name + "', '" + id + "', '" + password + "');";

String query = "INSERT INTO " + this.dbTableName + " (name, id, password) VALUES('" + name + "', '" + id + "', '" + password + "');''";

위에꺼가 맞는거다. 변수의 값을 문자로 보내주기 위해서 '변수명'으로 넣어주려는 것으로 ); 앞뒤로 ' ' 을 쓰는게 아니다.

 

3. Request를 받아 DataReader를 시켜 DB에 쿼리를 보내고, View를 시켜 Response를 보내는 @RequestMapping을 만들자.(HomeController.java)

	@RequestMapping(value = "/signup", method = RequestMethod.GET)
	public String signup(Locale locale, Model model) {

		return "signup";
	}
	
	// signup 페이지에 '회원가입'버튼을 만들고, 그 버튼을 누를 경우 무언가 기능을 실행시키도록 명령할 request를 만든다.
	// 데이터를 감추기 위해 request 방식은 POST 방식으로 바꾼다.
	@RequestMapping(value = "/signup_action", method = RequestMethod.POST)	// 어떤 Request를 받으면 동작할건가?
	public String signupAction(Locale locale, Model model, HttpServletRequest request) throws UnsupportedEncodingException {
		request.setCharacterEncoding("UTF-8");		// UTF-8 인코딩.
		String name = request.getParameter("name");		// name이라는 파라미터의 값을 얻는다.
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		
		// DataReader에 Insert 쿼리를 보내는 메소드를 만들고 그것을 실행하도록 명령을 내린다.
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		
		dataReader.open();		// DataReader를 연다.
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");	// SHA 알고리즘 클래스 호출.
			byte[] hash = digest.digest(password.getBytes("UTF-8"));	// 암호화 할 데이터를 "UTF-8"로 읽어 위에서 만든 알고리즘을 이용해 해쉬를 한다.
			StringBuffer hexString = new StringBuffer();				// 문자열을 잠시 담기 위한 버퍼 호출.
			
			// 해쉬한 문자열을 16진수(hex)로 바꿔주는 로직.
			for (int i = 0; i < hash.length; i++) {
				String hex = Integer.toHexString(0xff & hash[i]);
				if (hex.length() == 1) {
					hexString.append('0');
				}
				hexString.append(hex);
			}
			
			// 이 위에는 password 변수가 담은 값을 SHA-256을 하는 과정이고, 실제 DB에 Insert 쿼리를 보내는건 아래 한 줄이다.
			dataReader.insertData(name, id, hexString.toString());		// password 변수 대신 hexString.toString()을 넣어야 SHA-256 암호화 한 데이터를 보낸다.
			
		} catch (Exception ex) {
			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
		}
		dataReader.close();		// DataReader를 닫는다.
		
		return "signup";	// 어떤 View를 통해 Response를 보낼 것인가?
	}

'1234'로 입력한 비밀번호가 SHA-256으로 암호화 되어 들어갔다.

 

Statement를 PreparedStatement로 바꿔보자

	// signupAction을 Statement에서 PreparedStatement로 바꿔보자.
	public int insertData(String name, String id, String password) throws SQLException {
		String query = "INSERT INTO " + this.dbTableName + " (name, id, password) VALUES(?, ?, ?);";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);	// PreparedStatement를 이용해 접속 엔진을 연다.
		preparedStatement.setString(1, name);	// 1번째 물음표에 name을 넣는다.
		preparedStatement.setString(2, id);		// 2번째 물음표에 id를 넣는다.
		preparedStatement.setString(3, password);
		int result = preparedStatement.executeUpdate();	// 엔진을 이용해 쿼리를 보낸다.
		preparedStatement.close();		// 접속 엔진을 닫는다.

		return result;
	}

Statement는 쿼리문을 그대로 한 줄로 넣고,

PreparedStatement는 쿼리문에서 파라미터를 따로 분리한다.

 

 

4. 기능 만들기 (R : Select)

아이디를 생성했으니 로그인을 해보자.

1. View를 수정하자.(signin.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
	<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/sign_up.css">
    <title>로그인</title>
  </head>
  <body>
  	<h3>로그인</h3>
  	<a href="/Users/">홈으로</a><br /><br />
  	
    <form action="/Users/signin_action" method="post">
      ID <input type="text" name="id" placeholder="아이디를 입력해주세요" />
      <br />
      PW <input type="text" name="password" placeholder="패스워드를 입력해주세요" />
      <br />
      <input type="submit" value="로그인" />
    </form>
  </body>
</html>

 

2. DB와 통신하는 Model를 수정하자.(DataReader.java)

	// signinAction에 대한 Select 쿼리를 날려주는 메소드를 생성한다.
	public boolean signin(String id, String password) throws SQLException {
		boolean result = false;
		String query = "SELECT * FROM " + this.dbTableName + " WHERE id=? AND password=?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setString(1, id);
		preparedStatement.setString(2, password);
		ResultSet resultSet = preparedStatement.executeQuery(); // ResultSet은 쿼리 결과를 그대로 받아온다.
		if (resultSet.next()) {
			result = true;	// ResultSet을 이용해 일치하면 return값인 result에 boolean 형태의 값을 넣너준다.
		}
		resultSet.close();				// 반드시 닫아준다!
		preparedStatement.close();		// 반드시 닫아준다!
		
		return result;
	}

 

3. Request를 받아 DataReader를 시켜 DB에 쿼리를 보내고, View를 시켜 Response를 보내는 @RequestMapping을 만들자.(HomeController.java)

	@RequestMapping(value = "/signin", method = RequestMethod.GET)
	public String signin(Locale locale, Model model) {

		return "signin";
	}
	
    // @RequestParam으로 받을 경우 한글이 깨진다. (영어는 괜찮음. 이 경우는 id, password 모두 영어만 있어서 괜찮지만 위 signupAction처럼 HttpServletRequest request로 통일시키자.
	@RequestMapping(value = "/signin_action", method = RequestMethod.POST)
	public String signinAction(Locale locale, Model model, HttpServletRequest request, 
			@RequestParam("id") String id,
			@RequestParam("password") String password) {
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		boolean result = false;
		
		dataReader.open();		// DataReader를 연다.
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			byte[] hash = digest.digest(password.getBytes("UTF-8"));
			StringBuffer hexString = new StringBuffer();
			
			// 해쉬한 문자열을 16진수(hex)로 바꿔주는 로직.
			for (int i = 0; i < hash.length; i++) {
				String hex = Integer.toHexString(0xff & hash[i]);
				if (hex.length() == 1) {
					hexString.append('0');
				}
				hexString.append(hex);
			}

			result = dataReader.signin(id, hexString.toString());		// DB에 SHA-256으로 해시한 암호가 저장되어 있으니 사용자가 입력한 암호 역시 SHA-256으로 해시해서 보내야 일치하는지 판별이 가능하다. 
			
		} catch (Exception ex) {
			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
		}
		dataReader.close();		// DataReader를 닫는다.

		if (result) {
			HttpSession session = request.getSession();
			session.setAttribute("is_login", "true");
			return "success";			
		} else {
			return "fail";
		}
	}
    
    // 가급적 signupAction처럼 HttpServletRequest를 이용해 .getParameter(); 를 이용하는 방식으로 통일시키자.(한글 깨짐 방지)
    @RequestMapping(value = "/signin_action", method = RequestMethod.POST)
	public String signinAction(Locale locale, Model model, HttpServletRequest request) throws UnsupportedEncodingException {
		request.setCharacterEncoding("UTF-8");		// UTF-8 인코딩.
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		boolean result = false;
		
		dataReader.open();		// DataReader를 연다.
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			byte[] hash = digest.digest(password.getBytes("UTF-8"));
			StringBuffer hexString = new StringBuffer();
			
			// 해쉬한 문자열을 16진수(hex)로 바꿔주는 로직.
			for (int i = 0; i < hash.length; i++) {
				String hex = Integer.toHexString(0xff & hash[i]);
				if (hex.length() == 1) {
					hexString.append('0');
				}
				hexString.append(hex);
			}

			result = dataReader.signin(id, hexString.toString());		// DB에 SHA-256으로 해시한 암호가 저장되어 있으니 사용자가 입력한 암호 역시 SHA-256으로 해시해서 보내야 일치하는지 판별이 가능하다. 
			
		} catch (Exception ex) {
			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
		}
		dataReader.close();		// DataReader를 닫는다.

		if (result) {
			HttpSession session = request.getSession();
			session.setAttribute("is_login", "true");
			return "success";			
		} else {
			return "fail";
		}
	}

 

결과를 보여줄 View(success, fail)을 만들자

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>signin success</title>
</head>
<body>
	<p>로그인 되었습니다.</p>
	<a href="/Users/">홈으로</a>
</body>
</html>

 

fail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>signin fail</title>
</head>
<body>
	<p>로그인에 실패하였습니다. 아이디와 비밀번호를 확인하세요.</p>
	<a href="/Users/">홈으로</a>&nbsp;&nbsp;<a href="/Users/signin">로그인 페이지로 돌아가기</a>
</body>
</html>

 

5. 기능 만들기 (로그인 세션 확인하고 로그아웃 만들기)

private.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>
  </head>
  <body>
  	<h3>비밀 페이지 입니다.</h3>
  	<a href="/Users/">홈으로</a>
  </body>
</html>

 

HomeController

	// 로그인 세션 확인 페이지로 이동.
	@RequestMapping(value = "/private", method = RequestMethod.GET)
	public String privatePage(Locale locale, Model model, HttpServletRequest request) {
		HttpSession session = request.getSession();
		String isLogin = (String)session.getAttribute("is_login");
		if (isLogin != null && isLogin.equals("true")) {
			return "private";
		}
		return "signin";		
	}
	
	// 세션 로그아웃.
	@RequestMapping(value = "/signout", method = RequestMethod.GET)
	public String logout(Locale locale, Model model, HttpServletRequest request) {
		HttpSession session = request.getSession();
		session.invalidate();	// 세션을 무효화한다.
		return "signin";
	}

 

6. 기능 만들기 (DB 데이터 테이블로 뿌리기)

home.jsp

테이블을 추가한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
	<head>
		<title>Home</title>
		<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/home.css">
	</head>
	<body>
		<h1>
			User Data
		</h1>
		<a href="/Users/private">개인정보</a><br />
		<a href="/Users/signin">로그인</a>&nbsp;&nbsp;<a href="/Users/signout">로그아웃</a>&nbsp;&nbsp;<a href="/Users/signup">회원가입</a><br/><br/>
		<table>
			<thead>
				<tr>
					<th>idx</th><th>이름</th><th>아이디</th><th></th>
				</tr>
			</thead>
			<tbody>
				${userInfo }
			</tbody>
		</table>
	</body>
</html>

 

DataReader.java

	public String selectData() throws SQLException {
		boolean result = false;
		String query = "SELECT * FROM " + this.dbTableName + " WHERE ?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setInt(1, 1);
		ResultSet resultSet = preparedStatement.executeQuery();
		String htmlText = "";
		while (resultSet.next()) {
			String idx = resultSet.getString("idx");
			String name = resultSet.getString("name");
			String id = resultSet.getString("id");
			htmlText = htmlText 
					+ String.format("<tr>"
							+ "<td>%s</td>"
							+ "<td>%s</td>"
							+ "<td>%s</td>"
							+ "<td><a href='/Users/modify?idx=%s'>수정하기</a></td>",
							idx, name, id, idx);
		}
		resultSet.close();
		preparedStatement.close();
		return htmlText;
	}
htmlText = htmlText + String.format("<tr><td>%s</td><td>%s</td><td>%s</td><td><a href='/Users/modify?idx=%s'>수정하기</a></td>", idx, name, id, idx);

이렇게 한 줄로 쓰고 엔터 치면 + 버튼은 알아서 들어간다.

 

HomeController.java

DataReader를 시켜서 SELECT 쿼리를 보내고, Home(View)를 이용해 Response를 한다.

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		
		// DB 테이블 존재 유무를 콘솔에 출력.
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		File f = new File(dbUrl);
		if (f.exists()) {
			System.out.println("DB 테이블 있음.");
		} else {
			System.out.println("DB 테이블 없음.");
		}
		
		// DB 에서 읽어온 데이터를 테이블로 뿌리기
		DataReader dataReader = new DataReader(dbUrl, "users");
		dataReader.open();
		try {
			String result = dataReader.selectData();
			model.addAttribute("userInfo", result);
		} catch (Exception e) {

		}
		dataReader.close();
		
		return "home";
	}

'수정하기'버튼을 누르면 URL이 이렇게 뜨면 된다.(해당 URL 접속 후의 기능은 아직 구현하지 않았고 URL이 뜨는 것만 확인하면 됩니다.)

(idx=13인 홍길동의 '수정하기'를 누른 결과)

 

7. 기능 만들기 (U : Update)

modify.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/sign_up.css">
		<title>정보수정</title>
	</head>
	<body>
		<h1>정보수정</h1>
		<a href="/Users/">홈으로</a><br /><br />
		
		<!-- form 태그는 type="submit" 버튼을 누르면 action을 실행한다. name은 각각 파라미터 이름이 되고, 입력된 값은 각 파라미터의 값이 된다. HomeController에서 HttpServletRequest가 .getParameter를 통해 파라미터와 값에 접근한다. -->
	 	<form action="/Users/modify_action" method = "post">
	 		<input type="hidden" name="dix" value="${idx }" />	<!-- value에 DB에 있는 현재 정보를 불러와 띄워준다. -->
	 		이름 <input type="text" name="name" placeholder="이름을 입력해주세요" value="${name }" />
		    <br />
		    ID <input type="text" name="id" placeholder="아이디를 입력해주세요"  value="${id }" />
<!-- 		    <br />
		    <input type="password" name="password" placeholder="패스워드를 입력해주세요" /> -->
		    <br /><br />
	    	<input type="submit" name="" value="수정하기" />
	 	</form>
	 	
	</body>
</html>

 

User.java 클래스를 만들어 객체로 관리해보자

package com.KOPO.Users;

public class User {
	int idx;
	String name;
	String id;
	String password;
}

 

DataReader.java (객체를 이용하는 방식 - modify)

	public User selectData(String idx) throws SQLException {
		boolean result = false;
		String query = "SELECT * FROM " + this.dbTableName + " WHERE idx=?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setString(1, idx);
		ResultSet resultSet = preparedStatement.executeQuery();
		User selectedUser = new User();
		if (resultSet.next()) {
			selectedUser.idx = resultSet.getInt("idx");
			selectedUser.name = resultSet.getString("name");
			selectedUser.id = resultSet.getString("id");
		}
		resultSet.close();
		preparedStatement.close();
		return selectedUser;
	}

 

HomeController.java (객체를 이용하는 방식 - modify)

	@RequestMapping(value = "/modify", method = RequestMethod.GET)
	public String modify(Locale locale, Model model, @RequestParam("idx") String idx) {
		model.addAttribute("idx", idx);
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		dataReader.open();
		try {
			User sUser = dataReader.selectData(idx);	// 자료형:User 클래스, 변수명:sUser, 값:DataReader가 SELECT한 idx 번호의 객체 row.
			model.addAttribute("name", sUser.name);
			model.addAttribute("id", sUser.id);
		} catch (Exception e) {
			// TODO: handle exception
		}
		dataReader.close();

		return "modify";
	}

 

DataReader.java (객체를 이용하는 방식 - modify_action)

	public void updateData(String idx, String name, String id) throws SQLException {
		String query = "UPDATE " + this.dbTableName + " SET name=?, id=? WHERE idx=?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setString(1, name);
		preparedStatement.setString(2, id);
		preparedStatement.setString(3, idx);
		int result = preparedStatement.executeUpdate();
		preparedStatement.close();
	}
	
	public void updateData(String idx, String name, String id) throws SQLException {
		String query = "UPDATE " + this.dbTableName + " SET name='" + name + "', id='" + id + "' WHERE idx=" + idx + ";";
		Statement statement = this.connection.createStatement();
		int result = statement.executeUpdate(query);
		statement.close();
	}

 

HomeController.java (객체를 이용하는 방식 - modify_action)

	@RequestMapping(value = "/modify_action", method = RequestMethod.POST)
	public String modifyAction(Locale locale, Model model, HttpServletRequest request) throws UnsupportedEncodingException {
		request.setCharacterEncoding("UTF-8");		// UTF-8 인코딩.
		String idx = request.getParameter("idx");
		String id = request.getParameter("id");
		String name = request.getParameter("name");
		
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		
		dataReader.open();		// DataReader를 연다.
		try {
			dataReader.updateData(idx, name, id);			
		} catch (Exception ex) {
			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
		}
		dataReader.close();		// DataReader를 닫는다.

		return "modify";
	}

 

 

cf. 쿼리 보내기

String query =
PreparedStatement preparedStatement = this.connection.prepareStatement(query);
int result = preparedStatement.executeUpdate();   또는   ResultSet resultSet = preparedStatement.executeQuery();

String query =
Statement statement = this.connection.createStatement();
int result = statement.executeUpdate(query);   또는   ResultSet resultSet = statement.executeQuery(query);

1) PreparedStatement Statement query를 쓰는 위치가 다르다.
2) int result  쿼리의 실행 결과 return값이 없어도 되지만, ResultSet resultSet  쿼리의 실행 결과 return값이 반드시 필요하다. ResultSet은 쿼리의 실행 결과를 ResultSet이라는 객체로 받는다. 따라서, INSERT, UPDATE와 같은 return값이 없는 쿼리의 경우는 int result 를 써야하고, SELECT와 같이 return값이 있는 쿼리의 경우는 ResultSet resultSet 를 써서 return값을 객체로 받아야 다시 HomeController에 return을 할 수 있다.

 

cf. DataReader 메소드의 return 형태에 따른 차이

	public int 메소드(인풋 파라미터) throws SQLException {
		String query = 
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);	// PreparedStatement를 이용해 접속 엔진을 연다.
		preparedStatement.setString(1, 값);
		preparedStatement.setString(2, 값);
		int result = preparedStatement.executeUpdate();	// .executeQuery()의 return값은 boolean이라 int result에 담을 수 없다. 최종 return값인 result가 int형태기 때문에 .executeUpdate()로 쿼리를 보내야한다. 
		preparedStatement.close();

		return result;		// return값은 int 형태여야한다. (하지만 위 HomeController는 이 메소드를 호출한 다음 return값은 받지 않는다. 메소드는 return을 보내지만 HomeController에서 return값을 받지 않음.)
	}
    
    

	public boolean 메소드(인풋 파라미터) throws SQLException {
		boolean result = false;
		String query = 
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setString(1, 값);	// 1번째 물음표
		preparedStatement.setString(2, 값);	// 2번째 물음표
		ResultSet resultSet = preparedStatement.executeQuery(); // ResultSet은 쿼리 결과를 그대로 받아온다.
		if (resultSet.next()) {
			result = true;	// ResultSet을 이용해 일치하면 return값인 result에 boolean 형태의 값을 넣너준다.
		}
		resultSet.close();
		preparedStatement.close();
		
		return result;		// return값은 boolean 형태여야한다. (위 HomeController에서 return값을 받아 사용한다.)
	}

 

cf. 세션 처리

@RequestMapping의 메소드가 인풋 파라미터로 HttpServletRequest request를 미리 인스턴스화 해놔야한다.

// 세션에 저장하기
HttpSession session = request.getSession();
session.setAttribute(String "변수명", Object 값);

// 세션 불러오기
HttpSession session = request.getSession();
String 변수명 = (String)session.getAttribute("변수명");

// 세션 종료
HttpSession session = request.getSession();
session.invalidate();

 

cf. HTML 테이블 형태로 데이터를 내보내기 (DataReader -> HomeController -> VIew)

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
    	DataReader dataReader = new DataReader(dbUrl, "tableName");
		dataReader.open();
		try {
			String result = dataReader.selectData();
			model.addAttribute("userInfo", result);
		} catch (Exception e) {
			e.printStackTrace();
		}
		dataReader.close();
        
	return "home";

 

 

완성본 모음

더보기

HomeController.java

package com.KOPO.Users;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

	// 1. 메인 홈
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		
		// DB 테이블 존재 유무를 콘솔에 출력.
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		File f = new File(dbUrl);
		if (f.exists()) {
			System.out.println("DB 테이블 있음.");
		} else {
			System.out.println("DB 테이블 없음.");
		}
		
		// DB 에서 읽어온 데이터를 테이블로 뿌리기
		DataReader dataReader = new DataReader(dbUrl, "users");
		dataReader.open();
		try {
			String result = dataReader.selectData();
			model.addAttribute("userInfo", result);
		} catch (Exception e) {

		}
		dataReader.close();
		
		return "home";
	}
	
	// 2. 회원가입
	@RequestMapping(value = "/signup", method = RequestMethod.GET)
	public String signup(Locale locale, Model model) {

		return "signup";
	}
	
	// signup 페이지에 '회원가입'버튼을 만들고, 그 버튼을 누를 경우 무언가 기능을 실행시키도록 명령할 request를 만든다.
	// 데이터를 감추기 위해 request 방식은 POST 방식으로 바꾼다.
	@RequestMapping(value = "/signup_action", method = RequestMethod.POST)	// 어떤 Request를 받으면 동작할건가?
	public String signupAction(Locale locale, Model model, HttpServletRequest request) throws UnsupportedEncodingException {
		request.setCharacterEncoding("UTF-8");		// UTF-8 인코딩.
		String name = request.getParameter("name");		// name이라는 파라미터의 값을 얻는다.
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		
		// DataReader에 Insert 쿼리를 보내는 메소드를 만들고 그것을 실행하도록 명령을 내린다.
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		
		dataReader.open();		// DataReader를 연다.
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");	// SHA 알고리즘 클래스 호출.
			byte[] hash = digest.digest(password.getBytes("UTF-8"));	// 암호화 할 데이터를 "UTF-8"로 읽어 위에서 만든 알고리즘을 이용해 해쉬를 한다.
			StringBuffer hexString = new StringBuffer();				// 문자열을 잠시 담기 위한 버퍼 호출.
			
			// 해쉬한 문자열을 16진수(hex)로 바꿔주는 로직.
			for (int i = 0; i < hash.length; i++) {
				String hex = Integer.toHexString(0xff & hash[i]);
				if (hex.length() == 1) {
					hexString.append('0');
				}
				hexString.append(hex);
			}
			
			// 이 위에는 password 변수가 담은 값을 SHA-256을 하는 과정이고, 실제 DB에 Insert 쿼리를 보내는건 아래 한 줄이다.
			dataReader.insertData(name, id, hexString.toString());		// password 변수 대신 hexString.toString()을 넣어야 SHA-256 암호화 한 데이터를 보낸다.
			
		} catch (Exception ex) {
			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
		}
		dataReader.close();		// DataReader를 닫는다.
		
		return "signup";	// 어떤 View를 통해 Response를 보낼 것인가?
	}
	
	// 3. 로그인
	@RequestMapping(value = "/signin", method = RequestMethod.GET)
	public String signin(Locale locale, Model model) {

		return "signin";
	}
	
	// @RequestParam으로 받을 경우 한글이 깨진다. (영어는 괜찮음. 이 경우는 id, password 모두 영어만 있어서 괜찮지만 위 signupAction처럼 HttpServletRequest request로 통일시키자.
//	@RequestMapping(value = "/signin_action", method = RequestMethod.POST)
//	public String signinAction(Locale locale, Model model, HttpServletRequest request, 
//			@RequestParam("id") String id,
//			@RequestParam("password") String password) {
//		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
//		DataReader dataReader = new DataReader(dbUrl, "users");
//		boolean result = false;
//		
//		dataReader.open();		// DataReader를 연다.
//		try {
//			MessageDigest digest = MessageDigest.getInstance("SHA-256");
//			byte[] hash = digest.digest(password.getBytes("UTF-8"));
//			StringBuffer hexString = new StringBuffer();
//			
//			// 해쉬한 문자열을 16진수(hex)로 바꿔주는 로직.
//			for (int i = 0; i < hash.length; i++) {
//				String hex = Integer.toHexString(0xff & hash[i]);
//				if (hex.length() == 1) {
//					hexString.append('0');
//				}
//				hexString.append(hex);
//			}
//
//			result = dataReader.signin(id, hexString.toString());		// DB에 SHA-256으로 해시한 암호가 저장되어 있으니 사용자가 입력한 암호 역시 SHA-256으로 해시해서 보내야 일치하는지 판별이 가능하다. 
//			
//		} catch (Exception ex) {
//			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
//		}
//		dataReader.close();		// DataReader를 닫는다.
//
//		if (result) {
//			HttpSession session = request.getSession();
//			session.setAttribute("is_login", "true");
//			return "success";			
//		} else {
//			return "fail";
//		}
//	}
	
	@RequestMapping(value = "/signin_action", method = RequestMethod.POST)
	public String signinAction(Locale locale, Model model, HttpServletRequest request) throws UnsupportedEncodingException {
		request.setCharacterEncoding("UTF-8");		// UTF-8 인코딩.
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		boolean result = false;
		
		dataReader.open();		// DataReader를 연다.
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			byte[] hash = digest.digest(password.getBytes("UTF-8"));
			StringBuffer hexString = new StringBuffer();
			
			// 해쉬한 문자열을 16진수(hex)로 바꿔주는 로직.
			for (int i = 0; i < hash.length; i++) {
				String hex = Integer.toHexString(0xff & hash[i]);
				if (hex.length() == 1) {
					hexString.append('0');
				}
				hexString.append(hex);
			}

			result = dataReader.signin(id, hexString.toString());		// DB에 SHA-256으로 해시한 암호가 저장되어 있으니 사용자가 입력한 암호 역시 SHA-256으로 해시해서 보내야 일치하는지 판별이 가능하다. 
			
		} catch (Exception ex) {
			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
		}
		dataReader.close();		// DataReader를 닫는다.

		if (result) {
			HttpSession session = request.getSession();
			session.setAttribute("is_login", "true");
			return "success";			
		} else {
			return "fail";
		}
	}
	
	// 3.2 로그인 세션 확인 및 로그아웃
	// 로그인 세션 확인 페이지로 이동.
	@RequestMapping(value = "/private", method = RequestMethod.GET)
	public String privatePage(Locale locale, Model model, HttpServletRequest request) {
		HttpSession session = request.getSession();
		String isLogin = (String)session.getAttribute("is_login");
		if (isLogin != null && isLogin.equals("true")) {
			return "private";
		}
		return "signin";		
	}
	
	// 세션 로그아웃.
	@RequestMapping(value = "/signout", method = RequestMethod.GET)
	public String logout(Locale locale, Model model, HttpServletRequest request) {
		HttpSession session = request.getSession();
		session.invalidate();	// 세션을 무효화한다.
		return "signin";
	}
	
	// 4. 정보수정
	@RequestMapping(value = "/modify", method = RequestMethod.GET)
	public String modify(Locale locale, Model model, @RequestParam("idx") String idx) {
		model.addAttribute("idx", idx);
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		dataReader.open();
		try {
			User sUser = dataReader.selectData(idx);	// 자료형:User 클래스, 변수명:sUser, 값:DataReader가 SELECT한 idx 번호의 객체 row.
			model.addAttribute("name", sUser.name);
			model.addAttribute("id", sUser.id);
		} catch (Exception e) {
			// TODO: handle exception
		}
		dataReader.close();

		return "modify";
	}
	
	@RequestMapping(value = "/modify_action", method = RequestMethod.POST)
	public String modifyAction(Locale locale, Model model, HttpServletRequest request) throws UnsupportedEncodingException {
		request.setCharacterEncoding("UTF-8");		// UTF-8 인코딩.
		String idx = request.getParameter("idx");
		String id = request.getParameter("id");
		String name = request.getParameter("name");
		
		String dbUrl = "//Users//꿈나무//SqliteDB//users.sqlite";
		DataReader dataReader = new DataReader(dbUrl, "users");
		
		dataReader.open();		// DataReader를 연다.
		try {
			dataReader.updateData(idx, name, id);			
		} catch (Exception ex) {
			throw new RuntimeException(ex);		// RuntimeException을 추가한다.
		}
		dataReader.close();		// DataReader를 닫는다.

		return "modify";
	}
	
}

 

DataReader.java

package com.KOPO.Users;

import java.sql.Connection;
import java.sql.DriverManager;
import org.sqlite.SQLiteConfig;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;

public class DataReader {
	private Connection connection;
	private String dbfileName;
	private String dbTableName;
	static {
		try {
			Class.forName("org.sqlite.JDBC");
			
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	public DataReader(String databaseFileName, String dbTableName) {
		this.dbfileName = databaseFileName;
		this.dbTableName = dbTableName;
	}
	public boolean open() {
		try {
			SQLiteConfig config = new SQLiteConfig();
			this.connection = DriverManager.getConnection("jdbc:sqlite:/" + 
			this.dbfileName, config.toProperties());
		}catch(SQLException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public boolean close() {
		if(this.connection == null) {
			return true;
		}
		try { 
			this.connection.close();
			
		}catch(SQLException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	// 1. 메인 홈
	public String selectData() throws SQLException {
		boolean result = false;
		String query = "SELECT * FROM " + this.dbTableName + " WHERE ?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setInt(1, 1);
		ResultSet resultSet = preparedStatement.executeQuery();
		String htmlText = "";
		while (resultSet.next()) {
			String idx = resultSet.getString("idx");
			String name = resultSet.getString("name");
			String id = resultSet.getString("id");
			htmlText = htmlText 
					+ String.format("<tr>"
							+ "<td>%s</td>"
							+ "<td>%s</td>"
							+ "<td>%s</td>"
							+ "<td><a href='/Users/modify?idx=%s'>수정하기</a></td>",
							idx, name, id, idx);
		}
		resultSet.close();
		preparedStatement.close();
		return htmlText;
	}
	
	// 2. 회원가입
	// signupAction에 대한 Insert 쿼리를 날려주는 메소드를 생성한다.
//	public int insertData(String name, String id, String password) throws SQLException {
//		String query = "INSERT INTO " + this.dbTableName + " (name, id, password) VALUES('" + name + "', '" + id + "', '" + password + "');";
//		Statement statement = this.connection.createStatement();	// Statement를 이용해 접속 엔진을 연다.
//		int result = statement.executeUpdate(query);	// 엔진을 이용해 쿼리를 보낸다.
//		statement.close();		// 접속 엔진을 닫는다.
//		
//		return result;
//	}
	
	// signupAction을 Statement에서 PreparedStatement로 바꿔보자.
	public int insertData(String name, String id, String password) throws SQLException {
		String query = "INSERT INTO " + this.dbTableName + " (name, id, password) VALUES(?, ?, ?);";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);	// PreparedStatement를 이용해 접속 엔진을 연다.
		preparedStatement.setString(1, name);	// 1번째 물음표에 name을 넣는다.
		preparedStatement.setString(2, id);		// 2번째 물음표에 id를 넣는다.
		preparedStatement.setString(3, password);
		int result = preparedStatement.executeUpdate();	// 엔진을 이용해 쿼리를 보낸다.
		preparedStatement.close();		// 접속 엔진을 닫는다.

		return result;
	}
	
	// 3. 로그인
	// signinAction에 대한 Select 쿼리를 날려주는 메소드를 생성한다.
	public boolean signin(String id, String password) throws SQLException {
		boolean result = false;
		String query = "SELECT * FROM " + this.dbTableName + " WHERE id=? AND password=?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setString(1, id);
		preparedStatement.setString(2, password);
		ResultSet resultSet = preparedStatement.executeQuery(); // ResultSet은 쿼리 결과를 그대로 받아온다.
		if (resultSet.next()) {
			result = true;	// ResultSet을 이용해 일치하면 return값인 result에 boolean 형태의 값을 넣너준다.
		}
		resultSet.close();				// 반드시 닫아준다!
		preparedStatement.close();		// 반드시 닫아준다!
		
		return result;
	}
	
	// 4. 정보수정 (객체를 return하는 selectData를 만든다. 위 selectData는 인풋 파라미터가 없었다. 다형성을 이용해 구분한다.)
	public User selectData(String idx) throws SQLException {
		boolean result = false;
		String query = "SELECT * FROM " + this.dbTableName + " WHERE idx=?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setString(1, idx);
		ResultSet resultSet = preparedStatement.executeQuery();
		User selectedUser = new User();
		if (resultSet.next()) {
			selectedUser.idx = resultSet.getInt("idx");
			selectedUser.name = resultSet.getString("name");
			selectedUser.id = resultSet.getString("id");
		}
		resultSet.close();
		preparedStatement.close();
		return selectedUser;
	}
	
	public void updateData(String idx, String name, String id) throws SQLException {
		String query = "UPDATE " + this.dbTableName + " SET name=?, id=? WHERE idx=?;";
		PreparedStatement preparedStatement = this.connection.prepareStatement(query);
		preparedStatement.setString(1, name);
		preparedStatement.setString(2, id);
		preparedStatement.setString(3, idx);
		int result = preparedStatement.executeUpdate();
		preparedStatement.close();
	}
	
//	public void updateData(String idx, String name, String id) throws SQLException {
//		String query = "UPDATE " + this.dbTableName + " SET name='" + name + "', id='" + id + "' WHERE idx=" + idx + ";";
//		Statement statement = this.connection.createStatement();
//		int result = statement.executeUpdate(query);
//		statement.close();
//	}
	
}

 

User.java

package com.KOPO.Users;

public class User {
	int idx;
	String name;
	String id;
	String password;
}

 

home.css

@charset "UTF-8";

table {
	border-collapse: collapse;
	width: 90%;
	margin: 0 auto;
}

td, th {
	padding: 5px;
	text-align: center;
}

th {
	background: #A4A4A4;
	color: #fff;
}

td a {
	background: #84FA7A;
	padding: 5px 20px;
	text-decoration: none;
	border-radius: 5px;
}

  

sign_up.css

form {
  width: 500px;
  padding: 40px;
  background: #eee;
  border-radius: 10px;
  margin: 0 auto;
}

form input[type="text"], form input[type="password"] {
  width: 100%;
  margin: 10px 0px;
  padding: 10px;
}

form input[type="submit"] {
  display: block;
  padding: 10px 100px;
  margin: 0 auto;
}

  

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
	<head>
		<title>Home</title>
		<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/home.css">
	</head>
	<body>
		<h1>
			User Data
		</h1>
		<a href="/Users/private">개인정보</a><br /> <!-- /Users/ 는 생략 가능하다. private만 써도 된다. -->
		<a href="/Users/signin">로그인</a>&nbsp;&nbsp;<a href="/Users/signout">로그아웃</a>&nbsp;&nbsp;<a href="/Users/signup">회원가입</a><br/><br/>
		<table>
			<thead>
				<tr>
					<th>idx</th><th>이름</th><th>아이디</th><th></th>
				</tr>
			</thead>
			<tbody>
				${userInfo }
			</tbody>
		</table>
	</body>
</html>

  

signup.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/sign_up.css">
		<title>회원가입</title>
	</head>
	<body>
		<h1>회원가입</h1>
		<a href="/Users/">홈으로</a><br /><br />
		
		<!-- form 태그는 type="submit" 버튼을 누르면 action을 실행한다. name은 각각 파라미터 이름이 되고, 입력된 값은 각 파라미터의 값이 된다. HomeController에서 HttpServletRequest가 .getParameter를 통해 파라미터와 값에 접근한다. -->
	 	<form action="/Users/signup_action" method = "post">
	 		이름 <input type="text" name="name" placeholder="이름을 입력해주세요" />
		    <br />
		    ID <input type="text" name="id" placeholder="아이디를 입력해주세요" />
		    <br />
		    PW <input type="password" name="password" placeholder="패스워드를 입력해주세요" />
		    <br /><br />
	    	<input type="submit" name="" value="회원가입" />
	 	</form>
	 	
	</body>
</html>

 

signin.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
	<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/sign_up.css">
    <title>로그인</title>
  </head>
  <body>
  	<h3>로그인</h3>
  	<a href="/Users/">홈으로</a><br /><br />
  	
    <form action="/Users/signin_action" method="post">
      ID <input type="text" name="id" placeholder="아이디를 입력해주세요" />
      <br />
      PW <input type="text" name="password" placeholder="패스워드를 입력해주세요" />
      <br />
      <input type="submit" value="로그인" />
    </form>
  </body>
</html>

  

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>signin success</title>
</head>
<body>
	<p>로그인 되었습니다.</p>
	<a href="/Users/">홈으로</a>
</body>
</html>

 

fail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>signin fail</title>
</head>
<body>
	<p>로그인에 실패하였습니다. 아이디와 비밀번호를 확인하세요.</p>
	<a href="/Users/">홈으로</a>&nbsp;&nbsp;<a href="/Users/signin">로그인 페이지로 돌아가기</a>
</body>
</html>

  

private.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>
  </head>
  <body>
  	<h3>비밀 페이지 입니다.</h3>
  	<a href="/Users/">홈으로</a>
  </body>
</html>

  

modify.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/sign_up.css">
		<title>정보수정</title>
	</head>
	<body>
		<h1>정보수정</h1>
		<a href="/Users/">홈으로</a><br /><br />
		
		<!-- form 태그는 type="submit" 버튼을 누르면 action을 실행한다. name은 각각 파라미터 이름이 되고, 입력된 값은 각 파라미터의 값이 된다. HomeController에서 HttpServletRequest가 .getParameter를 통해 파라미터와 값에 접근한다. -->
	 	<form action="/Users/modify_action" method = "post">
	 		<input type="hidden" name="idx" value="${idx }" />	<!-- value에 DB에 있는 현재 정보를 불러와 띄워준다. -->
	 		이름 <input type="text" name="name" placeholder="이름을 입력해주세요" value="${name }" />
		    <br />
		    ID <input type="text" name="id" placeholder="아이디를 입력해주세요"  value="${id }" />
<!-- 		    <br />
		    <input type="password" name="password" placeholder="패스워드를 입력해주세요" /> -->
		    <br /><br />
	    	<input type="submit" name="" value="수정하기" />
	 	</form>
	 	
	</body>
</html>

 

 

java.sql.SQLException: opening db: '/.//users.sqlite': Read-only file system

파일을 내장 디스크가 아닌 외장 디스크에 만들 경우 이런다. 777옵션 줘도 동일한 에러가 발생한다.

DB파일을 내장 디스크에 위치시여야 작동한다.

이유가 뭘까....? 아마 톰캣이 디스크 접근 권한을 갖지 못하는 것 같은데... 접근 권한을 주려고 해도 톰캣 자체가 포터블 형식인데다 맥에서 실행 파일로 안 잡혀서 그런지 권한을 실행 파일 목록에 뜨질 않는다......

 

그냥 DB 파일은 맥 내장 디스크에 위치시켜 해결하는 것으로...

Could not publish server configuration for Tomcat v9.0 Server at localhost.

Context with path "/users" conflicts with another Context with path "/Users

 

같은 웹 접속 경로를 사용해서 충돌이 난다.

해결을 위해 서버 탭에서 톰캣 서버를 더블 클릭해 연다.

 

하단의 'Modules'를 누르고 들어가서 'Web Modules'에 중복되는 것을 제거한 다음 실행한다. (지워도 나중에 서버 실행시 등록한다고 물어보니 걱정하지 말고 지우자.)

계속 자바 CRUD를 추가해서 배우고 있다...

그리고 이날 오후는 지난번 했던 블록체인 코드를 각 조별로 교수님과 모여 코드리뷰 후 별도의 브랜치로 올리거나 병합하는 작업을 했다. 마스터 브랜치가 달라질 경우 기존 브랜치에 연결하는 것은 웹상에선 불가능하단 것을 알았다. 가급적 띄어쓰기 등도 바꾸지 않고 정말 수정한 부분만 딱딱 바꿔야 conflict가 나지 않고 잘 된다는 것도... 다 경험이다.

'개발자 > TIL' 카테고리의 다른 글

TIL 20.06.07  (0) 2020.06.07
TIL 20.06.06  (0) 2020.06.07
TIL 20.06.04  (0) 2020.06.04
TIL 20.06.03  (0) 2020.06.04
TIL 20.06.02  (0) 2020.06.02

HomeController의 locale

사용자의 언어, 국가뿐 아니라 사용자 인터페이스에서 사용자가 선호하는 사항을 지정한 매개 변수의 모임이다.

쉽게 말해서

한국 : 2020년 6월 5일, 섭씨, kg, m, ...
미국 : June 5, 2020, 화씨, lbs, peet, ...

 

HomeController의 model

데이터 -> model -> View

HomeController가 DataReader를 시켜 DB에서 데이터를 받아와 리턴한다. 그러면 HomController의 mode이 그 데이터를 받아 View에 넘겨주는 역할을 한다.

model.addAttribute("query_result", dataReader.selectData());

이 model이 호출될 때 보면 'public String home(Locale locale, Model model) {   }' 이런식으로 호출된다.

즉, Model이라는 클래스를 model이라는 변수명으로 호출하고, 이 클래스가 가지고 있는 addAttribute라는 메소드를 이용하는 것이다.

이 addAttribute 메소드는 "query_result"라는 변수에 dataReader가 selectData 메소드를 실행해 return한 값을 받아오는데, 그 값이 들어간다.
즉, String abc = "안녕하세요" 처럼
query_result = 'selectData의 return값'을 변수로 받게 되고, 그 값을 View에 던져주는 기능이다.

자바스크립트로 서버를 이용한 CRUD를 했다.

아직은 미숙한 아주아주 기초적인 방식으로...

값을 가져오거나 하는 부분이 너무 헷갈린다...

'개발자 > TIL' 카테고리의 다른 글

TIL 20.06.06  (0) 2020.06.07
TIL 20.06.05  (0) 2020.06.06
TIL 20.06.03  (0) 2020.06.04
TIL 20.06.02  (0) 2020.06.02
TIL 20.06.01  (0) 2020.06.02

파이썬 머신러닝을 배웠다...

수업이 끝나고 남은건 오류 난 빨간 블럭들 뿐 ㅠㅠ

'개발자 > TIL' 카테고리의 다른 글

TIL 20.06.05  (0) 2020.06.06
TIL 20.06.04  (0) 2020.06.04
TIL 20.06.02  (0) 2020.06.02
TIL 20.06.01  (0) 2020.06.02
TIL 20.05.30  (0) 2020.05.31

1. Enum이란?

Enum 열거형(Enumerated Type)이라고 부릅니다. 해당 언어의 상수 역할을 하는 식별자, 일부 열거자 자료형은 언어에 기본으로 포함되어 있습니다. 대표적인 예가 Boolean 자료형으로 False, True 값이 미리 정의된 열거형으로 있습니다. False == 0, True == 1 이죠.

그리고 대부분의 언어는 사용자가 자신만의 Enum 직접 만들어 관리할 있도록 해줍니다.

 

2. 파이썬에도 Enum이 있을까?

파이썬은 2.x 버전에서는 Enum 없었습니다. Python 3.4에서 추가되었습니다. 해당 소스 코드는 Lib/enum.py 정의되어 있습니다.

 

3. 파이썬에서 Enum을 사용해보자!

우선 파이썬에서 Enum을 사용하기 위해서는 모듈(라이브러리)를 먼저 import 해야합니다.

from enum import Enum

그리고 Enum을 상속 받는 클래스를 만듭니다.

class Rainbow(Enum):
    Red = 0
    Orange = 1
    Yellow = 2
    Green = 3
    Blue = 4
    Navy = 5
    Purple = 6

자료형을 확인해보니 enum 형태의 'Rainbow'로 확인됩니다.

 

4. 직접 만든 Enum을 사용해보자!

호출하는 방법은 2가지가 있습니다.

얼핏 보면 Key : Value 형식으로 보이지만 딕셔너리가 작동하는 것과는 다릅니다.

딕셔너리에서는 Key를 호출하면 Value가 나왔지만 Enum은 HTML 태그의 작동 방식과 더 유사합니다.

 

이런식으로 name과 value를 호출하는 방식으로 사용합니다.

 

그렇다면 Enum을 이렇게 사용할 수도 있겠죠.

class Port(Enum):
    SSH = 22
    Telnet = 23
    SMTP = 25
    HTTP = 80
    HTTPS = 443

이런식으로 자동완성을 이용해 편리하게 사용할 수 있으며 연관된 집단끼리 클래스로 묶어 관리를 할 수 있습니다.

 

그러면 Enum은 왜 쓸까?

특정 상태를 하나의 집합으로 만들어 관리함으로써 코드를 정리하는데 수월합니다. , 가독성 높아지고 문서화 하는데 도움이 됩니다.

 

Enum에 대한 몇 가지 팁

다른 언어에서는 기본적으로 Enum을 상속 받도록 만든 다음, 내가 커스터마이징하려는 변수만 선언을 하면 값을 지정하지 않아도 기본값이 0, 1, 2, ... 이런식으로 설정이 되지만, 아쉽게도 파이썬은 모든 변수를 직접 지정해줘야합니다.

일일히 할당하기 귀찮은데 어쩌죠?

Enum 불러오지 않고 import enum 해서 전체를 불러올 경우 enum 안에 있는 auto() 함수를 이용할  있습니다. 그러면 자동으로 1, 2, 3, … 이런식으로 설정이 됩니다. 하지만 모든 변수에 = enum.auto() 직접 입력해줘야 하는 것은 동일하기 때문에 다른 언어와 비교해 자동 할당으로써의 의미는 떨어집니다.

import enum

class Rainbow(enum.Enum):
    Red = enum.auto()
    Orange = enum.auto()
    Yellow = enum.auto()
    Green = enum.auto()
    Blue = enum.auto()
    Navy = enum.auto()
    Purple = enum.auto()

 

이것도 귀찮은데요? 그리고 파이썬 최신 버전이 아닌 경우는 사용 못 하나요?

파이썬에서 Enum을 지원하기 이전에 사용하던 방법을 써도 됩니다.

Enum을 직접 함수로 만들어 사용하는 것입니다!

def myEnum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

이렇게 myEnum이라는 함수를 만들어 사용할 수 있습니다.

Rainbow = myEnum('Red','Orange','Yellow','Green','Blue','Navy','Purple')

이렇게 하면 

자동으로 번호가 입력됩니다.

 

프로젝트를 하다보면 파이썬 최신 버전이 아닌 곳이 있을 수도 있습니다. 아직 파이썬 2.x 버전을 사용하는 곳도 있을 수 있으니 그런 곳에서는 이런식으로 함수를 만들어 사용하면 됩니다.

+ Recent posts