1. 정리 1의 Create에 DB 생성과 실패에 따른 결과를 받아 테이블 생성/실패 처리 추가하기

HomeController

	// 쿼리를 이용해 테이블 생성하기.
	@RequestMapping(value = "/create", method = RequestMethod.GET)
	public String create(Locale locale, Model model) {
		DB db = new DB<Student>(".../student.db", "student");
//		DB db = new DB<Color>(".../color.db", "color");
//		DB db = new DB<Color>(".../memo.db", "memo");
		
		if (db.open()) {
			if (db.createTable(new Student())) {
//			if (db.createTable(new Color())) {
//			if (db.createTable(new Memo())) {
				model.addAttribute("message", "테이블이 생성되었습니다.");
			} else {
				model.addAttribute("message", "테이블 생성에 실패하였습니다.");
			}
			db.close();
		} else {
			model.addAttribute("message", "DB파일을 사용할 수 없습니다.");
		}
		
		return "message";
	}

 

DB

	// create table 쿼리 실행
	public boolean createTable(T t) {	// 기존에는 Student student라고 해서 Student라는 객체가 들어온다 명시를 했다. T는 어떤 객체가 들어올지 모른단 뜻. DB를 DB<T>로 Generic(제네릭)을 사용한다.
		Class<?> dataClass = t.getClass();	// t의 Class Object를 가져와 return해서 dataClass라는 변수명에 저장.
		Field[] dataClassFields = dataClass.getDeclaredFields();	// dataClass라는 클래스의 변수들을 array로 return.
		
		String fieldString = "";
		
		for (Field field: dataClassFields) {	//  array로부터 for each 문을 돌면서 하나씩 분해해 쿼리에 넣을 문자열을 만든다.
			if (!fieldString.isEmpty()) {
				fieldString = fieldString + ",";
			}
			String fieldName = field.getName();
			String fieldType = field.getType().toString();
			fieldString = fieldString + fieldName;
			if (fieldName.matches("idx")) {
				fieldString = fieldString + " INTEGER PRIMARY KEY AUTOINCREMENT";
			} else if (fieldType.matches("(int|long)")) {
				fieldString = fieldString + " INTEGER";
			} else if (fieldType.matches("(float|double)")) {
				fieldString = fieldString + " REAL";
			} else if (fieldType.matches(".*String")) {
				fieldString = fieldString + " TEXT";
			}
		}
		
		String query = "CREATE TABLE " + this.tableName + " (" + fieldString + ")";
		try {
			Statement statement = this.connection.createStatement();
			statement.executeUpdate(query);
			statement.close();
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

 

 

2. 이번에는 Insert를 만들자.

HomeController

	// 데이터 입력하기.
	@RequestMapping(value = "/insert", method = RequestMethod.GET)
	public String insert(Locale locale, Model model,
			@RequestParam("name") String name,
			@RequestParam("middleScore") int middleScore,
			@RequestParam("finalScore") int finalScore) {
		DB db = new DB<Student>(".../student.db", "student");
		
		if (db.open()) {
			if (db.insertData(new Student(name, middleScore, finalScore))) {
				model.addAttribute("message", "새 데이터를 추가했습니다.");
			} else {
				model.addAttribute("message", "데이터 추가에 실패했습니다.");
			};
			db.close();
		} else {
			model.addAttribute("message", "DB파일을 사용할 수 없습니다.");
		}
		
		return "message";
	}

 

DB

	// insert 쿼리 실행
	public boolean insertData(T t) {
		Class<?> dataClass = t.getClass();
		Field[] dataClassFields = dataClass.getDeclaredFields();
		
		String fieldString = "";
		String valueString = "";
		
		for (Field field: dataClassFields) {
			String fieldName = field.getName();
			String fieldType = field.getType().toString();
			if (fieldName.matches("idx")) {
				continue;
			}
			if (!fieldString.isEmpty()) {
				fieldString = fieldString + ",";
			}
			if (!valueString.isEmpty()) {
				valueString = valueString + ",";
			}
			fieldString = fieldString + fieldName;
			
			// DB 컬럼에 넣을 값. 값이 문자열이면 ' ' 로 감싸주고, 그렇지 않으면 그냥 입력.
			try {
				if (fieldType.matches(".*String")) {	// 문자열이면 ' '로 감싸준다.
					valueString = valueString + "'" + field.get(t) + "'";
				} else {								// 아니면 그냥 넣는다.
					valueString = valueString + field.get(t);
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		
		// 위에서 구한 fieldString(name, middleScore, finalScore...)와 valueString("홍길동", 100, 80)을 넣어 쿼리문을 만든다.
		String query = "INSERT INTO " + this.tableName + " (" + fieldString + ") VALUES(" + valueString + ")";
		try {
			Statement statement = this.connection.createStatement();
			statement.executeUpdate(query);
			statement.close();
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

 

URL에 쿼리를 보내서 입력해보자.

http://localhost:8099/student/insert?name=홍길동&middleScore=100&finalScore=80
http://localhost:8099/student/insert?name=장보고&middleScore=70&finalScore=85
http://localhost:8099/student/insert?name=고길동&middleScore=90&finalScore=55

 

 

3. Update 만들기

HomeController

	// 데이터 수정하기.
	@RequestMapping(value = "/update", method = RequestMethod.GET)
	public String insert(Locale locale, Model model,
			@RequestParam("idx") int idx,
			@RequestParam("name") String name,
			@RequestParam("middleScore") int middleScore,
			@RequestParam("finalScore") int finalScore) {
		DB db = new DB<Student>(".../student.db", "student");
		
		if (db.open()) {
			if (db.insertData(new Student(idx, name, middleScore, finalScore))) {
				model.addAttribute("message", "데이터를 수정했습니다.");
			} else {
				model.addAttribute("message", "데이터 수정에 실패했습니다.");
			};
			db.close();
		} else {
			model.addAttribute("message", "DB파일을 사용할 수 없습니다.");
		}
		
		return "message";
	}

 

DB

	// update 쿼리 실행
	public boolean updateData(T t) {
		Class<?> dataClass = t.getClass();
		Field[] dataClassFields = dataClass.getDeclaredFields();
		String setString = "";
		String whereString = "";
		for (Field field : dataClassFields) {
			if (!setString.isEmpty()) {
				setString = setString + ",";
			}
			String fieldName = field.getName();
			String fieldType = field.getType().toString();
			try {
				if (fieldName.matches("idx")) {
					whereString = "idx=" + field.get(t);
				} else if (fieldType.matches(".*String")) {
					setString = setString + fieldName + "=" + "'" + field.get(t) + "'";
				} else {
					setString = setString + fieldName + "=" + field.get(t);
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		String query = "UPDATE " + this.tableName + " SET " + setString + " WHERE " + whereString;
		try {
			Statement statement = this.connection.createStatement();
			statement.executeUpdate(query);
			statement.close();
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

 

URL에  쿼리를 보내서 수정해보자.

http://localhost:8099/student/update?idx=1&name=홍길동&middleScore=100&finalScore=100

 

 

4. UTF-8 설정하기 & null 체크하기 & 숫자(numeric) 체크하기

STS 4 Spring Boot에서는 설정 안 해도 자동으로 UTF-8로 되지만 STS 3도 있으니까...

그리고 파라미터가 이름이 잘못 들어오거나 할 경우 400 에러가 뜨는데, 이런 것들이 보안 취약점이 되기 때문에 예외처리를 해준다.

UTF-8 처리

	// 데이터 입력하기.
	@RequestMapping(value = "/insert", method = RequestMethod.GET)
	public String insert(Locale locale, Model model, HttpServletRequest request) {
		try {
			request.setCharacterEncoding("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		String name = request.getParameter("name");
		int middleScore = Integer.parseInt(request.getParameter("middleScore"));
		int finalScore = Integer.parseInt(request.getParameter("finalScore"));
		
		DB db = new DB<Student>(".../student.db", "student");
		
		if (db.open()) {
			if (db.insertData(new Student(name, middleScore, finalScore))) {
				model.addAttribute("message", "새 데이터를 추가했습니다.");
			} else {
				model.addAttribute("message", "데이터 추가에 실패했습니다.");
			};
			db.close();
		} else {
			model.addAttribute("message", "DB파일을 사용할 수 없습니다.");
		}
		
		return "message";
	}

 

null 체크하기 (방법 1) try~catch & 숫자(numeric) 체크하기

	// 데이터 입력하기. try를 사용한 잘못된 파라미터 체크 & 문자열 숫자 형변환 가능 여부 검사하는 방법.
	@RequestMapping(value = "/insert", method = RequestMethod.GET)
	public String insert(Locale locale, Model model, HttpServletRequest request) {
		try {
			request.setCharacterEncoding("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
						
		DB db = new DB<Student>(".../student.db", "student");
		
		if (db.open()) {
			try {
				String name = request.getParameter("name");
				int middleScore = Integer.parseInt(request.getParameter("middleScore"));
				int finalScore = Integer.parseInt(request.getParameter("finalScore"));

				if (db.insertData(new Student(name, middleScore, finalScore))) {
					model.addAttribute("message", "새 데이터를 추가했습니다.");
				} else {
					model.addAttribute("message", "데이터 추가에 실패했습니다.");
				};
			} catch (Exception e) {
				model.addAttribute("message", "데이터가 올바르지 않습니다.");
			}

			db.close();
		} else {
			model.addAttribute("message", "DB파일을 사용할 수 없습니다.");
		}
		
		return "message";
	}

 

테스트용 URL

http://localhost:8099/student/insert?name=테스트1&middleScore=20&finalScore=20	// 정상인 경우
http://localhost:8099/student/insert?name=테스트2&middleScore=20&finalStore=20	// 파라미터 이름이 잘못 들어온 경우에 대한 null 체크
http://localhost:8099/student/insert?name=테스트3&middleScore=20a&finalScore=20	// 파라미터 이름은 정상이나 숫자가 들어와야 하는 곳에 문자가 들어오는 경우에 대한 예외처리
http://localhost:8099/student/insert?name=테스트3&middleScore=20&finalScore=	// 파라미터 이름은 정상이나 숫자가 들어와야 하는 곳에 빈 값이 들어온 경우에 대한 예외처리

 

null 체크하기 (방법 2) if & 숫자(numeric) 체크하기

	// 데이터 입력하기. if를 사용한 잘못된 파라미터 체크 & 문자열 숫자 형변환 가능 여부 검사하는 방법.
	@RequestMapping(value = "/insert", method = RequestMethod.GET)
	public String insert(Locale locale, Model model, HttpServletRequest request) {
		try {
			request.setCharacterEncoding("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		DB db = new DB<Student>(".../student.db", "student");
		
		if (db.open()) {
			if (request.getParameter("name") != null &&	// 파라미터 이름이 잘못 들어온 경우에 대한 null 체크
				request.getParameter("middleScore") != null &&
				isIntegerString(request.getParameter("middleScore")) &&	// 숫자로 형변환 가능한지를 체크 (파라미터 이름은 정상이나 숫자로 변환이 불가능하거나 빈 값에 대한 예외처리)
				request.getParameter("finalScore") != null &&
				isIntegerString(request.getParameter("finalScore")) &&
				db.insertData(new Student(request.getParameter("name"),	// 파라미터 가져오기
										  Integer.parseInt(request.getParameter("middleScore")),
										  Integer.parseInt(request.getParameter("finalScore"))))) {
				model.addAttribute("message", "새 데이터를 추가했습니다.");
			} else {
				model.addAttribute("message", "데이터 추가에 실패했습니다.");
			};
			db.close();
		} else {
			model.addAttribute("message", "DB파일을 사용할 수 없습니다.");
		}
		
		return "message";
	}

 

파라미터로 들어온 문자열이 숫자로 형변환 가능한지 아닌지를 검사하는 메소드를 만든다.

'java numeric string check' 등으로 검색한다.

	// String이 숫자로 형변환이 가능한지 아닌지를 검사하는 메소드
	private boolean isIntegerString(String numericString) {
		try {
			int result = Integer.parseInt(numericString);
			return true;
		} catch (Exception e) {
			
		}
		return false;
	}

 

테스트용 URL

http://localhost:8099/student/insert?name=테스트1&middleScore=20&finalScore=20	// 정상인 경우
http://localhost:8099/student/insert?name=테스트2&middleScore=20&finalStore=20	// 파라미터 이름이 잘못 들어온 경우에 대한 null 체크
http://localhost:8099/student/insert?name=테스트3&middleScore=20a&finalScore=20	// 파라미터 이름은 정상이나 숫자가 들어와야 하는 곳에 문자가 들어오는 경우에 대한 예외처리
http://localhost:8099/student/insert?name=테스트3&middleScore=20&finalScore=	// 파라미터 이름은 정상이나 숫자가 들어와야 하는 곳에 빈 값이 들어온 경우에 대한 예외처리

문자와 달리 숫자의 경우 형변환이 가능한지를 확인하는 것으로 숫자로 가능한 문자열인지에 대한 체크와 동시에 파라미터 이름은 정상이나 빈 값으로 들어오는 경우에 대한 예외처리를 동시에 할 수 있다.

발전 과제 : http://localhost:8099/student/insert?name=&middleScore=20&finalScore=20 // 파라미터 이름은 정상이나 문자가 들어와야 하는 곳에 빈 값이 들어온 경우에 대한 예외처리를 방법 1과 2 모두 처리하지 못 했다. replaceAll을 이용하면 처리가 되지만 이 경우 문자열 사이의 공백도 제거해버리기 때문에 사용할 수 없다. trim()으로 해보았으나 아예 "   " 인 경우는 trim이 작동하지 않고 빈 문자열로 그냥 통과해버렸다.

 

update도 마찬가지로 바꿔주자. 위 방법 1을 사용하였으며, 변수를 생성하는 대신 바로 Student에 넣었다.

	// 데이터 수정하기.
	@RequestMapping(value = "/update", method = RequestMethod.GET)
	public String update(Locale locale, Model model, HttpServletRequest request) {
		try {
			request.setCharacterEncoding("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		DB db = new DB<Student>(".../student.db", "student");
		
		if (db.open()) {
			try {
				if (db.updateData(new Student(Integer.parseInt(request.getParameter("idx")),
											  request.getParameter("name"),
											  Integer.parseInt(request.getParameter("middleScore")),
											  Integer.parseInt(request.getParameter("finalScore"))))) {
					model.addAttribute("message", "새 데이터를 수정했습니다.");
				} else {
					model.addAttribute("message", "데이터 수정에 실패했습니다.");
				};
			} catch (Exception e) {
				e.printStackTrace();
				model.addAttribute("message", "데이터가 올바르지 않습니다.");
			}

			db.close();
		} else {
			model.addAttribute("message", "DB파일을 사용할 수 없습니다.");
		}
		
		return "message";
	}

 

테스트용 URL

http://localhost:8099/student/update?idx=19&name=공룡&middleScore=10&finalScore=13

idx에 들어가는 숫자는 DB를 보고 조절한다.

발전 과제 : idx가 존재하지 않는 값을 넣으면... 쿼리는 정상적으로 보내지기 때문에 데이터 수정에 실패했다고 뜨지 않고 수정했다고 뜬다...

 

 

 

방법 1과 방법 2를 기능별 분류하는 등 다양한 표현 코드에 대해서는 정리 3편에서 이어서 한다.

2020/09/06 - [개발자/Java] - Java (자바) CRUD 정리 3 static

 

+ Recent posts