특정 숫자(신호)에 특정 문자를 대응해두고, 문자나 기호를 컴퓨터에 신호 형태로 저장하는 과정을 Character Encoding이라고 한다.
(신호에서 문자를 해석하는 과정은 Decoding)
public class AlphaToInteger {
// 숫자로만 이루어진 value 문자열이 입력된다고 가정
// 1. 각 글자를 숫자 데이텉로 해석
// 2. 48을 빼주면 숫자가 된다.
private int atoi(String value) {
int result = 0;
// TODO 문자열을 한글자(한 자리)씩 확인
boolean negative = false;
int i=0;
// 첫 번째 문자가 '-' 인지
if (value.charAt(i) == '-') {
negative = true;
i++;
}
for (; i < value.length() ; i++) {
// TODO 자릿수 변환
result *= 10;
// TODO 글자를 숫자로 변환
result += value.charAt(i) - '0';
}
if (negative) result *= -1;
return result;
}
public static void main(String[] args) {
AlphaToInteger atoi = new AlphaToInteger();
System.out.println(atoi.atoi("12345"));
System.out.println(atoi.atoi("-4291"));
}
}
public class IntegerToAlpha {
public String itoa(int value) {
StringBuilder answerBuilder = new StringBuilder();
// 음수인지 확인
boolean negative = false;
if (value < 0) {
negative = true;
value *= -1;
}
// TODO value가 0보다 큰 동안
while (value > 0) {
// TODO value를 10으로 나눈 나머지를 문자로 변환
char digitChar = (char) (value % 10 + '0');
answerBuilder.append(digitChar);
// TODO value 나누기 10
value /= 10;
}
if (negative) answerBuilder.append('-');
return answerBuilder.reverse().toString();
}
public static void main(String[] args) {
IntegerToAlpha itoa = new IntegerToAlpha();
System.out.println(itoa.itoa(-1234));
}
}
Target 의 특정 위치부터, Pattern 문자열과 완전히 일치하는지 검사
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
// qwertyuiuiuytrertyuiopopoiuytrqwertyuytrertywqwertyuiuytrewqwertyuiiuiuiytrewert
// qwert
// 0, 30, 45, 59
public class BFPatternMatching {
public void solution() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String target = br.readLine();
String pattern = br.readLine();
int tarIdx = 0;
int patIdx = 0;
// TODO tarIdx 전체 길이보다 작을 동안에 반복한다
// TODO 존재하는지만 검사하는 경우, patIdx가 pattern.length() 보다 작을 동안 반복한다.
while (tarIdx < target.length() && patIdx < pattern.length()) {
// TODO target[tarIdx]가 pattern[patIdx] 랑 다를 경우
if (target.charAt(tarIdx) != pattern.charAt(patIdx)) {
// TODO tarIdx를 여태까지 이동한 만큼 되돌린다 (i-j)
tarIdx -= patIdx;
// TODO patIdx를 -1로 할당한다.
patIdx = -1;
}
// TODO 다음칸으로 이동한다.
tarIdx++;
patIdx++;
}
// TODO patIdx == patter.length() 이면 성공 > 어디에서 찾았는지 출력
if (patIdx == pattern.length()) {
System.out.println(tarIdx-patIdx);
}
// TODO 못찾은 경우, System.out.println("404 Not Found")
else {
System.out.println("404 Not Found");
}
}
public static void main(String[] args) throws IOException {
new BFPatternMatching().solution();
}
}
null safety를 위한 클래스
자바 8버전에 처음 소개된 컨테이너 객체
NullPointException을 try-catch로 예외 처리 하지 않고 Optional로 감싸 처리할 수 있게 해줌
ofNullable()
메서드가 필요하지만 JpaRepository에서 반환된 값은 바로 Optional 반환함Optional<T>.orElse(T other)
: null
이면 T
타입의 other
반환 null
이 아니면 T
타입 그대로 반환
Optional<T>.orElse(null)
을 컨트롤러에 전달해서 404Error 를 의도적으로 발생시키는 방식으로도 사용 가능
View Layer(Client)와 통신하는 DTO 클래스는 자주 변경되지만 테이블에 매핑되는 Entity는 그에 비해 변경도 적고, 영향 범위도 매우 크다.
DTO가 일회성으로 데이터를 주고받는 용도로 사용되는 것과 다르게 Entity의 생명 주기(Life Cycle)도 전혀 다르다.
정보가 불일치 할 경우 : 테이블에 매핑되는 정보가 실제 View에서 원하는 정보와 다를 수 있다.
이러한 경우에는 변환하는 로직이 필요한데, 같이 쓰게 된다면 해당 로직이 Entity에 들어가게 되어서 Entity가 지저분해진다.
정보 노출 : DB 로부터 조회된 Entity 를 그대로 View로 넘길 경우 불필요한, 노출되면 안 되는 정보까지 노출될 수 있고, 이를 막기 위한 로직을 따로 구현해야 한다.
생성자 기법과는 별도로 생성만을 담당하는 클래스 메소드를 의미한다.
직접적인 생성자가 아닌 메소드를 통해 객체를 생성한다.
외부에서 요청이 들어오면 이에 맞게 객체를 생성하거나, 단순 반환해주는 것이 주된 역할이다.
생성자와는 달리 팩토리 메서드에는 이름이 있다.
(코드의 가독성이 높아지며 사용하기도 쉬워짐)
생성자와 달리 호출할 때마다 새로운 객체를 생성할 필요가 없다.
(동일한 객체가 요청되는 일이 잦고, 객체를 만드는 비용이 클 때 적용시키면 성능을 크게 개선이 가능)
생성자와 달리 반환값 자료형의 하위 자료형 객체를 반환할 수 있습니다.
(반환되는 객체의 클래스를 훨씬 유연하게 결정이 가능)
입력 매개변수에 따라 다른 클래스의 객체를 반환할 수 있습니다.
정적 팩토리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 됩니다.
package com.example.student.dto;
import com.example.student.entity.StudentEntity;
import lombok.Data;
@Data
public class StudentDto {
private Long id;
private String name;
private Integer age;
private String phone;
private String email;
// static factory method pattern
public static StudentDto fromEntity(StudentEntity entity) {
StudentDto dto = new StudentDto();
dto.setId(entity.getId());
dto.setName(entity.getName());
dto.setAge(entity.getAge());
dto.setPhone(entity.getPhone());
dto.setEmail(entity.getEmail());
return dto;
}
}
package com.example.student.entity;
/* CREATE TABLE students (
* id INTEGER PRIMARY KEY AUTOINCREMENT,
* name TEXT,
* age INTEGER,
* phone TEXT,
* email TEXT
* */
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
@Table(name = "students")
public class StudentEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
private String phone;
private String email;
}
package com.example.student.repository;
import com.example.student.entity.StudentEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository extends JpaRepository<StudentEntity, Long> {
}
package com.example.student;
import com.example.student.dto.StudentDto;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.ResponseStatusException;
@Controller
@RequestMapping("/students")
public class StudentController {
private final StudentService service;
public StudentController(StudentService service) {
this.service = service;
}
@GetMapping("")
public String home(Model model) {
model.addAttribute("studentList", service.readStudentAll());
return "home";
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
// create.html 응답
@GetMapping("/create-view")
public String createView() {
return "create";
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
// 새로운 StudentEntity 생성 후 상세보기 페이지로
@PostMapping("/create")
public String create(StudentDto dto) {
StudentDto newDto = service.createStudent(dto);
return "redirect:/students/" + newDto.getId();
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
// id에 해당하는 StudentEntity의 read.html 응답
@GetMapping("/{id}")
public String read(@PathVariable("id") Long id, Model model) {
service.readStudent(id);
model.addAttribute("student", service.readStudent(id));
return "read";
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
// id에 해당하는 StudentEntity의 update.html 응답
@GetMapping("/{id}/update-view")
public String updateView(@PathVariable("id") Long id, Model model){
model.addAttribute("student", service.readStudent(id));
return "update";
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
// id에 해당하는 StudentEntity 수정 후 상세보기 페이지로
@PostMapping("/{id}/update")
public String update(@PathVariable("id") Long id, StudentDto dto) {
StudentDto updateDto = service.updateStudent(id, dto);
return "redirect:/students/" + updateDto.getId();
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
// id에 해당하는 StudentEntity delete.html
@GetMapping("/{id}/delete-view")
public String deleteView(@PathVariable("id") Long id, Model model) {
model.addAttribute("student", service.readStudent(id));
return "delete";
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
// id에 해당하는 StudentEntity 삭제 후 홈페이지로
@PostMapping("/{id}/delete")
public String delete(@PathVariable("id") Long id) {
service.deleteStudent(id);
return "redirect:/students";
// throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED);
}
}
package com.example.student;
import com.example.student.dto.StudentDto;
import com.example.student.entity.StudentEntity;
import com.example.student.repository.StudentRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public class StudentService {
private final StudentRepository repository;
public StudentService(StudentRepository repository) {
this.repository = repository;
}
// CREATE
public StudentDto createStudent(StudentDto dto) {
StudentEntity newStudent = new StudentEntity();
newStudent.setName(dto.getName());
newStudent.setAge(dto.getAge());
newStudent.setPhone(dto.getPhone());
newStudent.setEmail(dto.getEmail());
return StudentDto.fromEntity(repository.save(newStudent));
}
// READ
public StudentDto readStudent(Long id) {
Optional<StudentEntity> optionalEntity = repository.findById(id);
if (optionalEntity.isPresent()) {
return StudentDto.fromEntity(optionalEntity.get());
} else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
// READ ALL
public List<StudentDto> readStudentAll() {
// 모든 entity 조회 repository method
List<StudentDto> studentDtoList = new ArrayList<>();
List<StudentEntity> studentEntityList = this.repository.findAll();
// 자유롭게
for (StudentEntity entity:
studentEntityList) {
studentDtoList.add(StudentDto.fromEntity(entity));
}
return studentDtoList;
}
// UPDATE
public StudentDto updateStudent(Long id, StudentDto dto) {
Optional<StudentEntity> optionalEntity = repository.findById(id);
if (optionalEntity.isPresent()) {
StudentEntity targetEntity = optionalEntity.get();
targetEntity.setName(dto.getName());
targetEntity.setAge(dto.getAge());
targetEntity.setPhone(dto.getPhone());
targetEntity.setEmail(dto.getEmail());
return StudentDto.fromEntity(repository.save(targetEntity));
} else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
// DELETE
public void deleteStudent(Long id) {
// repository.deleteById(id);
if(repository.existsById(id))
repository.deleteById(id);
else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
https://school.programmers.co.kr/learn/courses/30/lessons/120854
class Solution {
public int[] solution(String[] strlist) {
int[] answer = new int[strlist.length];
for (int i = 0; i < strlist.length; i++) answer[i] = strlist[i].length();
return answer;
}
}
https://school.programmers.co.kr/learn/courses/30/lessons/181937
class Solution {
public int solution(int num, int n) {
if (num % n == 0) return 1;
else return 0;
}
}
https://school.programmers.co.kr/learn/courses/30/lessons/181933
class Solution {
public int solution(int a, int b, boolean flag) {
if (flag == true) return a + b;
else return a - b;
}
}
easy
태환님의 문제 선정은 늘 옳다.
전체적으로 어려운 내용은 없었으나 여전히 익숙하지 않은 Spring의 실습은 하루종일 나를 피곤하게 만들었다. Students 프로젝트를 두 번째 해보지만 자주 들려오는 단어들(Entity, Optional, Dto ...)은 가끔 들리면서도 정확하게 무슨 의미인지는 아직도 잘 모르겠다.
이번 주는 너무나 힘들었던 것 같다. 수업듣고나서 밥먹고 포스팅만하고 씻고 잠만 자는데도 하루종일 피곤하고 정신이 없었던 것 같다. 어쩌다보니 팀원들과 다음 주에 아기사자반을 한 번 들어보기로 했다. 일단 금요일은 쉬고 주말에 복습을 해둬야겠다. 이번 주도 고생했다 우스가