알고리즘
문제 1. 별 찍기
*
**
***
****
*****
의 모양이 출력되도록 코드를 작성하시오.
Java
복사
package lecture.lecture_1017;
import java.util.Scanner;
public class RightTriangle {
public void getRightTriangle(int n){
for(int i =0;i<n;i++){
for(int j =0;j<=i;j++){
System.out.print("*");
}
System.out.println();
}
}
public static void main(String[] args) {
RightTriangle rt = new RightTriangle();
Scanner sc = new Scanner(System.in);
System.out.printf("개수를 입력하세요 : ");
int n = sc.nextInt();
rt.getRightTriangle(n);
}
}
Java
복사
문제 2. 생성자를 활용하여 다른 문자도 직각 삼각형의 모양으로 출력되도록 해보자.
package lecture.lecture_1017;
import java.util.Scanner;
public class RightTriangle {
private String letter = "*";
public RightTriangle(){}
public RightTriangle(String letter){
this.letter = letter;
}
public void getRightTriangle(int n){
for(int i =0;i<n;i++){
for(int j =0;j<=i;j++){
System.out.print(letter);
}
System.out.println();
}
}
public static void main(String[] args) {
RightTriangle rt = new RightTriangle("#");
Scanner sc = new Scanner(System.in);
System.out.printf("개수를 입력하세요 : ");
int n = sc.nextInt();
rt.getRightTriangle(n);
}
}
Java
복사
•
위의 로직은 생성자로 문자를 초기화 하도록 하였습니다.
◦
위 코드의 경우, “#” 를 객체 생성 시 전달해주어, #이 직각삼각형 모형으로 출력 되도록 하였습니다.
•
생성자 오버로딩
◦
위 코드의 경우, 생성자는 기본 생성자와, String 타입의 인자를 받는 생성자까지 총 2가지 존재합니다.
◦
생성자 오버로딩은, 매개변수의 타입과 개수가 다른 이름이 같은 생성자가 여러개 존재하는 것을 의미합니다.
◦
생성자 오버로딩은 파라미터가 존재하는 생성자와 기본값일 떄를 모두 사용하기 위해 사용합니다.
◦
따라서, 위의 코드는 생성자 오버로딩을 통해 “*”문자 뿐만 아니라, “#”, “!”등 원하는 문자를 출력할 수 있도록 String type의 문자열을 하나 받아 객체 생성 시 letter 값을 초기화 해주고 있음을 알 수 있습니다.
문제 3. 피라미드 별찍기
•
아래의 모양을 도출하는 코드를 작성하시오.
설계 문서 작성하기
1. 별의 입력은 홀수개만 입력 되도록 설계
i는 2k+1 일 경우에만 출력 (k=0,1,2,3….n)
2. 공백은 전체 길이 만큼 반복을 진행하며, 별이 출력되는 공간이 아닌 곳에 출력되도록 설계한다.
BASIC
복사
package lecture.lecture_1017;
public class Pyramid {
public void printPyramid(int n){
for(int i =0; i<n;i++){ //전체 길이 만큼 반복
for(int j=0;j<n-i;j++){ //공백 출력(전체 길이-i)만큼 계속 반복
System.out.print(" ");
}
for(int k=0; k<i*2+1; k++){
System.out.print("*");
}
System.out.println(" ");
}
}
public static void main(String[] args) {
Pyramid p = new Pyramid();
p.printPyramid(5);
}
}
Java
복사
동작 원리
자바 11 이상 Repeat() 메소드
repeat()
•
자바 11에서 새로 추가된 String 메서드 문자열을 파라미터의 주어진 횟수만큼 반복
•
내부적으로 Arrays.fill() 및 System.arraycopy() 메서드를 호출하여 새로운 문자열을 생성해줍니다.
예제 코드
package lecture.lecture_1017;
public class RepeatExample {
public static void main(String[] args) {
String str = "*";
System.out.println(str.repeat(50));
}
}
Java
복사
실행 결과
Java로 DB 연동
mysql dependency 추가
•
가장 최신 버전인 8.0.30 버전을 클릭합니다.
•
우리 프로젝트는 Gradle로 Build 했으므로, Gradle을 클릭하여 mysql 관련 라이브러리 연동 코드를 복사하여 가져와 줍니다.
인텔리제이에 붙혀 넣기
•
build,gradle → dependencies 부분에 추가
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
// https://mvnrepository.com/artifact/mysql/mysql-connector-java
implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.30'
}
test {
useJUnitPlatform()
}
BASIC
복사
•
가져온 이후에는 위에 코끼리 비슷한 모양을 클릭하여 작성한 코드가 적용되도록 꼭 한번 build 해주어야 합니다.
•
이제 우리는 자바에서 데이터베이스를 사용할 수 있습니다.
User VO 생성하기
•
VO(Value Object)
◦
값 오브젝트로, 값을 위해 쓰입니다.
◦
read-Only 특징을 가집니다.
◦
DTO와 비슷한 특성을 가지지만, DTO는 setter를 가지고 있어 값이 변할 수 있습니다.
◦
Value Object는 관계 데이터 베이스의 레코드에 대응되는 자바 클래스 입니다.
◦
형태는 db 레코드를 구성하는 필드들을 Value Object (Value 클래스)의 속성으로 설정 하고,
해당 변수에 접근할 수 있는 Getter, Setter 메소드의 조합으로 클래스가 형성 됩니다.
package org.example.domain;
public class User {
private String id;
private String name;
private String password;
public User(String id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Java
복사
•
우리는 User 테이블을 생성하고, 이 값들을 활용할 것이므로 VO로서 User 클래스를 하나 생성해줍니다.
•
이 클래스는 id, password, name 필드를 가집니다.
데이터베이스에 INSERT 역할을 하는 add() 메소드 작성하기
•
우리는 그동안 데이터베이스에 데이터를 INSERT 하기 위해 sql 문 형식의 내용이 저장된 파일을 생성한 뒤, workbench에서 그 파일을 찾아와 데이터 삽입 작업을 수행했습니다.
•
그러나 우리는 이제, 자바 위에서 Insert 해줄 수 있습니다.
•
아래 코드에서는 add() 메소드가 insert() 작업을 수행합니다.
package org.example.dao;
import org.example.FileManager;
import org.example.domain.User;
import org.example.parser.SqlParser;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class UserDao {
private final String jdbcDriver = "com.mysql.cj.jdbc.Driver";
//보안을 위해 설정한 환경변수 값들을 map으로 가져오기
private Map<String, String> env = System.getenv();
private String dbHost = env.get("DB_HOST");
private String dbUser = env.get("DB_USER");
private String dbPassword = env.get("DB_PASSWORD");
public void add(){
try{
//jdbc 로드
Class.forName(jdbcDriver);
//1. 커넥션 생성
Connection c = DriverManager.getConnection(dbHost, dbUser, dbPassword);
//2. 쿼리 작성
PreparedStatement ps = c.prepareStatement("INSERT INTO users values(?,?,?)");
ps.setString(1, "2");
ps.setString(2, "김길동");
ps.setString(3, "password");
//3. 쿼리 실행
ps.executeUpdate();
//4. 자원 반납
ps.close();
c.close();
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Java
복사
1. JDBC 로드
•
데이터베이스에 접속 하려면 해당 데이터베이스의 JDBC의 드라이버를 로드해야 합니다.
•
Class.forName(), 메소드를 호출하여 해당 클래스(데이터베이스 공급 업체에서 구현한 클래스)를 로드 해주는 방법을 사용합니다.
◦
우리의 경우 mysql을 활용.
2. 데이터베이스 연결
•
드라이버가 로드되면 해당 데이터베이스의 JDBC 드라이버를 이용해 프로그램을 작성할 수 있는 상태가 된 것을 의미합니다.
•
실제 데이터베이스와 연결하려면 Connection 클래스의 인스턴스가 필요
◦
우리는 DriverManager.getConnection()을 통해 이 인스턴스를 가져올 수 있습니다.
DriverManager. getConnection(JDBC_URL, “아이디”, “비밀번호”)
•
우리는, JDBC_URL 값과 데이터베이스 스키마의 아이디와 비밀번호를 환경 변수를 활용해 설정해주었습니다.
◦
모든 코드 정보를 git에 올려주어야 하는데, db 관련 정보가 노출되면 해킹 될 우려가 있습니다.
◦
그러므로, 노출되지 않도록, System.getenv()를 활용해줍니다.
◦
이를 활용하여, jdbc_url과 아이디, 비밀번호 값들을 설정해줍니다.
3. Statement 생성
•
Statement
◦
데이터베이스 연결로부터 SQL문을 수행할 수 있도록 해주는 클래스
◦
executeQuery()
▪
SELECT문을 수행할 때 사용
▪
반환 값은 ResultSet 클래스의 인스턴스로, 해당 SELECT문의 결과에 해당하는 데이터에 접근할 수 있는 방법을 제공.
◦
executeUpdate()
▪
UPDATE, DELETE와 같은 문을 수행할 때 사용
▪
반환 값은 int로, 처리된 데이터의 수를 반환.
•
우리 코드에서는 Connection 클래스의 prepareStatement() 메소드를 활용합니다.
◦
PreparedStatement
▪
SQL을 미리 만들어두고 변수를 따로 입력하는 방식
▪
효용성이나 유지보수 측면에서 유리한 구조
▪
Statement 클래스를 상속받기 때문에 Statement 클래스 메서드를 모두 사용
◦
SQL문에서 변수가 와야할 위치에는 물음표만 적어두고, 물음표 자리에는 setXXX() 메소드로 값을 설정합니다.
◦
예제 코드
PreparedStatement ps = c.prepareStatement("INSERT INTO users values(?,?,?)");
ps.setString(1, "2");
ps.setString(2, "김길동");
ps.setString(3, "password");
Java
복사
4. 사용한 자원 반납
•
PreparedStatement, Statement 모두 사용하지 않을 때는 닫아주어야 합니다.
•
close() 메소드를 통해 자원을 닫아줄 수 있습니다.
데이터의 조회 역할을 수행하는 Select 구현하기
package org.example.dao;
import org.example.FileManager;
import org.example.domain.User;
import org.example.parser.SqlParser;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class UserDao {
private final String jdbcDriver = "com.mysql.cj.jdbc.Driver";
//보안을 위해 설정한 환경변수 값들을 map으로 가져오기
private Map<String, String> env = System.getenv();
private String dbHost = env.get("DB_HOST");
private String dbUser = env.get("DB_USER");
private String dbPassword = env.get("DB_PASSWORD");
public User getUser(String id){
User user;
try{
Class.forName(jdbcDriver);
Connection c = DriverManager.getConnection(dbHost, dbUser, dbPassword);
PreparedStatement pstmt = c.prepareStatement("select * from users where id = ?");
pstmt.setString(1, id);
ResultSet rs = pstmt.executeQuery();
rs.next(); //하나 읽어오기
user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
rs.close();
pstmt.close();
c.close();
}catch (Exception e){
throw new RuntimeException(e);
}
return user;
}
}
Java
복사
•
JDBC 로드, 데이터베이스 연결(DriverManager.getConnection), PreparedStatement로 SQL문 작성하기의 과정은 위와 동일
•
select 즉 데이터 조회를 하려면, executeQuery()를 수행해주어야 합니다.
◦
executeQuery()는 ResultSet 타입의 인스턴스를 반환합니다.
•
ResultSet
◦
조회한 결과 값에 순차적으로 접근할 수 있는 커서를 다루게 합니다.
◦
DB 내부적으로 수행된 SQL문의 처리 결과를 JDBC에서 쉽게 관리하도록 해줌.
◦
커서를 최초 데이터 위치로 이동 시키기 위해 ResultSet이 반환하는 값을 활용하기 전에 rs.next() 메서드를 한 번 호출해준다.
•
읽어온 내용에서 getString() 메서드를 통해 로우에서 각 칼럼 값을 가져와줄 수 있다.
findAll() - 모든 유저 정보를 가져오기
package org.example.dao;
import org.example.FileManager;
import org.example.domain.User;
import org.example.parser.SqlParser;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class UserDao {
private final String jdbcDriver = "com.mysql.cj.jdbc.Driver";
//보안을 위해 설정한 환경변수 값들을 map으로 가져오기
private Map<String, String> env = System.getenv();
private String dbHost = env.get("DB_HOST");
private String dbUser = env.get("DB_USER");
private String dbPassword = env.get("DB_PASSWORD");
public List<User> findAll(){
List<User> userList = new ArrayList<>();
try {
Class.forName(jdbcDriver);
Connection c = DriverManager.getConnection(dbHost, dbUser, dbPassword);
Statement statement = c.createStatement();
ResultSet rs = statement.executeQuery("select * from users");
while (rs.next()) {
User user = new User(rs.getString("id"),
rs.getString("name"), rs.getString("password"));
userList.add(user);
}
rs.close();
statement.close();
c.close();
}catch(Exception e){
throw new RuntimeException(e);
}
return userList;
}
public static void main(String[] args) {
UserDao userDao = new UserDao();
List<User> allofUser = userDao.findAll();
for (User user : allofUser) {
System.out.println(user.getName());
}
}
}
Java
복사
•
JDBC 로드, 데이터베이스 연결, 쿼리문 생성은 위와 동일.
•
핵심은 while(rs.next()) 와 같이 로직을 작성하는 부분입니다.
◦
이는, 더이상 로우(레코드)가 없을 때 까지 루프를 돌면서 각 로우의 컬럼 값들을 User의 id, name, password의 인자값으로 설정해주고, User 인스턴스를 생성해줍니다.
•
모든 유저 정보를 가져와주기 위해 List를 활용해줍니다.
◦
while 루프를 돌면서 로우가 있는 동안, list에 생성된 User 타입의 인스턴스를 add() 메소드를 통해 추가해 줍니다.
•
메인 메소드에서 findAll() 메소드를 호출해 유저가 담긴 리스트를 얻고, for-each 문을 통해 모든 유저의 이름이 출력 되도록 하였습니다.