[LIKELION] 221028

고관운·2022년 10월 28일

회고

😄 느낀점

  • 배우고 싶었던 API를 공부하는 재미가 있다.
  • DB가 해킹을 당했다. 비밀번호를 바꾼 상태이긴 하지만 언제 다시 해킹당할 수 있는 상황이다. 보안이 중요하다는 것을 깨달았고 추후 실제 데이터베이스를 관리할 때 가장 신경쓸 부분인 것 같다.

😁 목표

  • 주말간 알고리즘 공부

알고리즘(Hash)

var 선언

타입 추론하여 정해줌

  • /인 경우 다른 타입이 나올 수 있어서 사용 자제할 것 - float, int 등 애매함
  • 어떤 타입이 들어갈지 명확한 경우에만 사용

폰켓몬(프로그래머스)

문제

👀 문제 확인하기 👀

방법

  1. HashSet 기능을 통한 중복 제거
  2. 폰켓몬 개수(nums.length) / 2, 폰켓몬 고유 개수 중 더 작은 값 리턴
import java.util.HashSet;

class Solution {
    public int solution(int[] nums) {
        int minValue = nums.length / 2;
        HashSet<Integer> set = new HashSet<>();

        // set 기능을 통한 중복 제거
        for (int num : nums) {
            set.add(num);
        }

        // 뽑을 수 있는 N/2와 폰켓몬의 고유값 중 작은 값을 리턴
        if (set.size() < minValue){
            minValue = set.size();
        }

        return minValue ;
    }
}

전화번호 목록(프로그래머스)

문제

👀 문제 확인하기 👀

방법

  1. 정수가 문자열 형태로 되어있는 리스트인 phone_book을 정렬하면 아래와 같은 형태로 정렬됨
    ["119", "97674223", "1195524421"] ➡ ["119", "1195524421", "97674223"]
    ["12","123","1235","567","88"] ➡ ["12","123","1235","567","88"]
  2. 1 ~ 마지막 전화번호까지 for문을 돌면서 전 전화번호가 현재 전화번호의 시작부분과 일치하는지 비교

🟢 "전화번호".startsWith("전화") : 전화번호의 앞부분이 전화인지 확인하고 맞으면 true 리턴

import java.util.Arrays;

class Solution {
    public boolean solution(String[] phone_book) {
        /*
         정렬하여 인덱스 차이가 1인 것끼리만 비교 가능
         문자열 정렬이기 때문에 아래와 같이 정렬됨 (오름차순이 아닌 첫째자리부터 더 작은 수가 오는 것이 앞에)
         ["119", "97674223", "1195524421"] -> ["119", "1195524421", "97674223"]
         ["12","123","1235","567","88"] -> ["12","123","1235","567","88"]
        */
        Arrays.sort(phone_book);

        // starsWith : phone_book[i]가 phone_book[i-1]로 시작하는지 확인
        for (int i = 1; i < phone_book.length; i++) {
            if(phone_book[i].startsWith(phone_book[i-1])){
                return false;
            }
        }
        return true;
    }
}

Spring Boot

Logback

Logback이란?

  • 로그를 남김(기록을 남기는 것)
  • 백엔드는 ui가 없기 때문에 많은 사람이 Logback을 사용
  • 에러가 났을 때 디버깅을 하기 위해 로그를 남김 or 분석용

Log 레벨

  • 뒤로 갈수록 적게 나오고 앞으로(TRACE쪽으로) 갈수록 많이 나옴
  • 가장 많이 쓰는 것은 INFO(기본값 INFO)
    (INFO면 INFO이하 다나옴 - WARN, ERROR까지)
    ex) INFO일때
TRACEDEBUGINFOWARNERROR
다 나옴조금 덜 나옴덜 나옴조금 나옴에러만 나옴

Log 레벨 나누는 이유

너무 많이 Log를 남기면 많은 값을 모두 볼 수 없기 때문

로그 레벨 변경 방법

application.yml에 코드 추가

logging:
  level:
    root: debug

로그 남기는 방법

  • 클래스 위에 @Slf4j 추가
  • 원하는 메서드 안에 log.info()하면 요청이 들어올 때 콘솔에 뜸
  • @PathVariable을 사용할 때 어떤 값이 들어왔는지 콘솔에 띄울 수도 있음
@RestController
@RequestMapping("/api/v1/get-api")
@Slf4j
public class GetController {
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello() {
        log.info("hello로 요청이 들어왔습니다");
        return "Hello World";
    }

    @GetMapping(value = "/name")
    public String getName() {
        log.info("getName으로 요청이 들어왔습니다");
        return "Kwanwun";
    }

    @GetMapping(value = "/variable1/{variable}")
    public String getVariable1(@PathVariable String variable) {
        log.info("getVariable1으로 요청이 들어왔습니다. variable: {}", variable);
        return variable;
    }
}

ORM

ORM이란

ORM(Object Realational Mapping)
자바 오프젝트(Class)하고 관계형 데이터베이스의 테이블과 매핑해주는 기능

  • 쿼리문을 ORM 프레임워크(ORM)이 작성해줌.
    (우리가 만든 UserDao도 SpringDataJPA(ORM)는 자동으로 해줌)
  • IoC, DI -> SpringDataJPA가 해줌
    (DataSource DI, StatementStrategy DI을 자동으로 해줌)

ORM 장단점

장점

  • 코드를 덜 짜도 됨

단점

  • 단독 사용이 어려움
  • 복잡한 서비스를 구현하기 어려움
  • 🔸초보자가 쓰기에 매우 위험함 👉 DB를 다 날릴 수 있음

SpringBoot로 CURD 게시판 API 구현하기

Layer 구조

  • Client : DELETE /user
  • Controller
    @Autowired
    UserDao userDao.deleteAll()
  • Business(Service)
  • Data Accecss(DAO) : this.jdbcTemplate.update("delete from users")

UserDao api연결 실습

목적
실습 SpringBoot와 jdbcTemplate을 이용해 기능 만들기
(https://github.com/Kyeongrok/springboot-jdbc-userdao 참고)

  • POST /user - user등록하는 기능
  • DELETE /user/{id} - 1명 유저 지우는 기능
  • DELETE /user/all - 전체 유저 지우는 기능
  • Get /user/{id} - id에 해당하는 것 가져오기
  • Get /user/all - 전체 유저 데이터 가져오기

실습하기 전 유용한 코드
1. 아래 두 코드는 같음

@Autowired
private UserDao userDao

private final UserDao userDao
  1. @AllArgsConstructor, @Getter
    조건 : lombok을 dependency에 추가(우리는 프로젝트에 체크했음)
    이 2개의 코드로 많은 코드 생략 가능
  • @AllArgsConstructor : 모든 변수를 갖고있는 생성자
  • @Getter : 모든 변수 getter 생성

실습 시작

  1. dependencies 추가

    • 'org.springframework.boot:spring-boot-starter-jdbc'
    • 'mysql:mysql-connector-java:8.0.30'
  2. UserDao, User추가 (DAO에서 했던 것 가져오기)

🟢 User

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 String getName() {
        return name;
    }

    public String getPassword() {
        return password;
    }
}

🟢 UserDao

import com.springboot.springbootcoreguide.domain.dao.User;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Component
public class UserDao {
    private final DataSource dataSource;
    private final JdbcTemplate jdbcTemplate;

    public UserDao(DataSource dataSource, JdbcTemplate jdbcTemplate) {
        this.dataSource = dataSource;
        this.jdbcTemplate = jdbcTemplate;
    }

    RowMapper<User> rowMapper = new RowMapper() {
        @Override
        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User(rs.getString("id"), rs.getString("name"),
                    rs.getString("password"));
            return user;
        }
    };

    public void add(User user) {
        this.jdbcTemplate.update("INSERT INTO users(id, name, password) VALUES (?, ?, ?)",
                user.getId(), user.getName(), user.getPassword());
    }

    public User findById(String id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        return this.jdbcTemplate.queryForObject(sql, rowMapper, id);
    }

    public List<User> getAll() {
        String sql = "SELECT * FROM users order by id";
        return this.jdbcTemplate.query(sql, rowMapper);
    }

    public void deleteById(String id) {
        this.jdbcTemplate.update("delete from users where id = ?", id);
    }

    public void deleteAll() {
        this.jdbcTemplate.update("delete from users");
    }

    public int getCount() {
        return this.jdbcTemplate.queryForObject("select count(*) from users", Integer.class);
    }
}
  1. application.yml에 DB연동 코드 추가
    🔴 해킹의 위험이 있기 때문에 localhost로 정해놓고 환경변수를 통해 값을 바꿔주는 형식으로
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/likelion-db
    username: root
    password: password

🔴 만약 환경변수 설정 옵션이 보이지 않는다면

🔴 입력할 값 : SPRING_DATASOURCE_URL=jdbc:mysql://<db_host>:3306/likelion-db
(SPRING_DATASOURCE_URL : 이것이 application.yml의 경로를 나타내는 것이기 때문에 꼭 대문자로 작성)

  1. UserController 추가한 후 기능 구현
import com.springboot.springbootcoreguide.dao.UserDao;
import com.springboot.springbootcoreguide.domain.dao.User;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/user")
public class UserController {
    private final UserDao userDao;

    public UserController(UserDao userDao) {
        this.userDao = userDao;
    }

    @PostMapping("")
    public String add(@RequestBody User user) {
        userDao.add(user);
        return String.format("%s번에 정보가 등록되었습니다.", user.getId());
    }

    @DeleteMapping(value = "/delete/{id}")
    public String deleteById(@PathVariable String id) {
        userDao.deleteById(id);
        return String.format("%s번의 정보가 삭제되었습니다.", id);
    }

    @DeleteMapping(value = "/delete/all")
    public String deleteAll() {
        userDao.deleteAll();
        return "모든 정보가 삭제되었습니다.";
    }

    @GetMapping(value = "/select/{id}")
    public String selectById(@PathVariable String id) {
        User selectedUser = userDao.findById(id);
        return String.format("id : %s\nname : %s\npassword : %s",
                selectedUser.getId(), selectedUser.getName(), selectedUser.getPassword());
    }

    @GetMapping(value = "/select/all")
    public String selectAll() {
        List<User> users = userDao.getAll();

        String str = "";

        for (User user : users) {
            str += String.format("id : %s\nname : %s\npassword : %s\n\n",
                    user.getId(), user.getName(), user.getPassword());
        }

        return str;
    }
}

0개의 댓글