Schedule
crud 기능에 대한 과제입니다. 일단 패키지는 controller,dto,entity,repository, service로 만들었습니다.
package com.example.schedule.controller;
import com.example.schedule.dto.ScheduleRequestDto;
import com.example.schedule.dto.ScheduleResponseDto;
import com.example.schedule.service.ScheduleService;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/schedules")
public class ScheduleController {
private final ScheduleService scheduleService;
public ScheduleController(ScheduleService scheduleService) {
this.scheduleService = scheduleService;
}
// 일정 등록
@PostMapping
public ResponseEntity<ScheduleResponseDto> createSchedule(@RequestBody ScheduleRequestDto dto) {
return new ResponseEntity<>(scheduleService.saveSchedule(dto), HttpStatus.CREATED);
}
// 전체 일정 조회
@GetMapping
public List<ScheduleResponseDto> findAllSchedules(){
return scheduleService.findAllSchedules();
}
// 선택 일정 조회
@GetMapping("/{id}")
public ResponseEntity<ScheduleResponseDto>findScheduleById(@PathVariable Long id){
return new ResponseEntity<>(scheduleService.findScheduleById(id),HttpStatus.OK);
}
// 선택 일정 수정
// @PostMapping("/{id}")
// 선택 일정 삭제
// @DeleteMapping("/{id}")
}
package com.example.schedule.service;
import com.example.schedule.dto.ScheduleRequestDto;
import com.example.schedule.dto.ScheduleResponseDto;
import java.util.List;
public interface ScheduleService {
ScheduleResponseDto saveSchedule(ScheduleRequestDto dto);
List<ScheduleResponseDto> findAllSchedules();
ScheduleResponseDto findScheduleById(Long id);
}
package com.example.schedule.service;
import com.example.schedule.dto.ScheduleRequestDto;
import com.example.schedule.dto.ScheduleResponseDto;
import com.example.schedule.entity.Schedule;
import com.example.schedule.repository.ScheduleRepository;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class ScheduleServiceImpl implements ScheduleService{
private final ScheduleRepository scheduleRepository;
public ScheduleServiceImpl(ScheduleRepository scheduleRepository) {
this.scheduleRepository = scheduleRepository;
}
// service) 일정 저장 메서드
@Override
public ScheduleResponseDto saveSchedule(ScheduleRequestDto dto) {
Schedule schedule = new Schedule(dto.getName(),dto.getPassword(),dto.getTodo(), LocalDateTime.now(),LocalDateTime.now());
return scheduleRepository.saveSchedule(schedule);
}
// service) 일정 목록 조회 메서드
@Override
public List<ScheduleResponseDto> findAllSchedules() {
return scheduleRepository.findAllSchedules();
}
// service) 일정 단건 조회 메서드
@Override
public ScheduleResponseDto findScheduleById(Long id) {
return new ScheduleResponseDto(scheduleRepository.findScheduleByIdOrElseThrow(id));
}
}
package com.example.schedule.repository;
import com.example.schedule.dto.ScheduleResponseDto;
import com.example.schedule.entity.Schedule;
import java.util.List;
public interface ScheduleRepository {
ScheduleResponseDto saveSchedule(Schedule schedule);
List<ScheduleResponseDto> findAllSchedules();
Schedule findScheduleByIdOrElseThrow(Long id);
}
package com.example.schedule.repository;
import com.example.schedule.dto.ScheduleResponseDto;
import com.example.schedule.entity.Schedule;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import org.springframework.web.server.ResponseStatusException;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Repository
public class ScheduleRepositoryImpl implements ScheduleRepository{
private final JdbcTemplate jdbcTemplate;
public ScheduleRepositoryImpl(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// repository) 일정 저장 메서드
@Override
public ScheduleResponseDto saveSchedule(Schedule schedule) {
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
simpleJdbcInsert.withTableName("schedule").usingGeneratedKeyColumns("id");
Map<String, Object> parameters = new HashMap<>();
parameters.put("name", schedule.getName());
parameters.put("password", schedule.getPassword());
parameters.put("todo", schedule.getTodo());
parameters.put("creationdate", schedule.getCreationdate());
parameters.put("modificationdate", schedule.getModificationdate());
Number key = simpleJdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
return new ScheduleResponseDto(key.longValue(), schedule.getName(),schedule.getTodo(),
schedule.getCreationdate(),schedule.getModificationdate());
}
// repository) 일정 목록 조회 메서드
@Override
public List<ScheduleResponseDto> findAllSchedules() {
return jdbcTemplate.query("select * from schedule order by modificationdate desc", scheduleRowMapper());
}
// repository) 일정 단건 조회 메서드
@Override
public Schedule findScheduleByIdOrElseThrow(Long id) {
List<Schedule> result = jdbcTemplate.query("select * from schedule where id = ?", scheduleRowMapperv2(), id);
return result.stream().findAny().orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Does not exists id = "+id));
}
// 각 행을 ScheduleResponseDto 타입으로 매핑 후 리스트로 반환해주는 메서드
private RowMapper<ScheduleResponseDto> scheduleRowMapper(){
return new RowMapper<ScheduleResponseDto>() {
@Override
public ScheduleResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
return new ScheduleResponseDto(rs.getLong("id"), rs.getString("name"),
rs.getString("todo"),
rs.getTimestamp("creationdate").toLocalDateTime(),
rs.getTimestamp("modificationdate").toLocalDateTime());
}
};
}
// 각 행을 Schedule 타입으로 매핑 후 리스트로 반환해주는 메서드
private RowMapper<Schedule> scheduleRowMapperv2() {
return new RowMapper<Schedule>() {
@Override
public Schedule mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Schedule(rs.getLong("id"),rs.getString("name"),rs.getString("password"),
rs.getString("todo"),rs.getTimestamp("creationdate").toLocalDateTime(),
rs.getTimestamp("modificationdate").toLocalDateTime());
}
};
}
}
package com.example.schedule.dto;
import lombok.Getter;
@Getter
public class ScheduleRequestDto {
private String name;
private String password;
private String todo;
}
package com.example.schedule.dto;
import com.example.schedule.entity.Schedule;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
@AllArgsConstructor
@Getter
public class ScheduleResponseDto {
private Long id;
private String name;
private String todo;
private LocalDateTime creationdate;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDateTime modificationdate;
public ScheduleResponseDto(Schedule schedule) {
this.id=schedule.getId();
this.name=schedule.getName();
this.todo=schedule.getTodo();
this.creationdate=schedule.getCreationdate();
this.modificationdate=schedule.getModificationdate();
}
}
package com.example.schedule.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
@AllArgsConstructor
@Getter
public class Schedule {
private Long id;
private String name;
private String password;
private String todo;
private LocalDateTime creationdate;
private LocalDateTime modificationdate;
public Schedule(String name, String password, String todo,
LocalDateTime creationdate,LocalDateTime modificationdate) {
this.name= name;
this.password = password;
this.todo = todo;
this.creationdate=creationdate;
this.modificationdate=modificationdate;
}
}
최대한 바뀐 부분만 올리려고 노력해보겠습니다..
// 선택 일정 조회
@GetMapping("/{id}")
public ResponseEntity<ScheduleResponseDto>findScheduleById(@PathVariable Long id){
return new ResponseEntity<>(scheduleService.findScheduleById(id),HttpStatus.OK);
}
// 선택 일정 수정
@PutMapping("/{id}")
public ResponseEntity<ScheduleResponseDto> updateSchedule(@PathVariable Long id, @RequestBody ScheduleRequestDto dto ){
return new ResponseEntity<>(scheduleService.updateSchedule(id,dto.getPassword(), dto.getName(),dto.getTodo()),HttpStatus.OK);
}
// 선택 일정 삭제
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteSchedule(@PathVariable Long id, @RequestBody ScheduleRequestDto dto){
scheduleService.deleteSchedule(id,dto.getPassword());
return new ResponseEntity<>(HttpStatus.OK);
}
package com.example.schedule.service;
import com.example.schedule.dto.ScheduleRequestDto;
import com.example.schedule.dto.ScheduleResponseDto;
import java.util.List;
public interface ScheduleService {
ScheduleResponseDto saveSchedule(ScheduleRequestDto dto);
List<ScheduleResponseDto> findAllSchedules();
ScheduleResponseDto findScheduleById(Long id);
ScheduleResponseDto updateSchedule(Long id,String password, String name, String todo);
void deleteSchedule(Long id,String password);
}
package com.example.schedule.service;
import com.example.schedule.dto.ScheduleRequestDto;
import com.example.schedule.dto.ScheduleResponseDto;
import com.example.schedule.entity.Schedule;
import com.example.schedule.repository.ScheduleRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class ScheduleServiceImpl implements ScheduleService{
private final ScheduleRepository scheduleRepository;
public ScheduleServiceImpl(ScheduleRepository scheduleRepository) {
this.scheduleRepository = scheduleRepository;
}
// service) 일정 등록 메서드
@Override
public ScheduleResponseDto saveSchedule(ScheduleRequestDto dto) {
Schedule schedule = new Schedule(dto.getName(),dto.getPassword(),dto.getTodo(), LocalDateTime.now(),LocalDateTime.now());
return scheduleRepository.saveSchedule(schedule);
}
// service) 일정 목록 조회 메서드
@Override
public List<ScheduleResponseDto> findAllSchedules() {
return scheduleRepository.findAllSchedules();
}
// service) 일정 단건 조회 메서드
@Override
public ScheduleResponseDto findScheduleById(Long id) {
return new ScheduleResponseDto(scheduleRepository.findScheduleByIdOrElseThrow(id));
}
// service) 일정 수정 메서드
@Transactional
@Override
public ScheduleResponseDto updateSchedule(Long id, String password, String name, String todo) {
if (name==null || todo==null || password==null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The name and todo and password is required values.");
}
if (password.equals(scheduleRepository.findScheduleByIdOrElseThrow(id).getPassword())) {
int updatedRow = scheduleRepository.updateSchedule(id, password,name, todo);
if (updatedRow==0) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND,"Does not exist id="+id);
}
Schedule schedule = scheduleRepository.findScheduleByIdOrElseThrow(id);
return new ScheduleResponseDto(schedule);
}
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "password is different");
}
// service) 일정 삭제 메서드
@Override
public void deleteSchedule(Long id,String password) {
if (password==null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The password is required values.");
}
if (password.equals(scheduleRepository.findScheduleByIdOrElseThrow(id).getPassword())) {
int deletedRow = scheduleRepository.deleteSchedule(id,password);
if(deletedRow==0) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND,"Does not exist id="+id);
}throw new ResponseStatusException(HttpStatus.OK);
}
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "password is different");
}
}
package com.example.schedule.repository;
import com.example.schedule.dto.ScheduleResponseDto;
import com.example.schedule.entity.Schedule;
import java.util.List;
public interface ScheduleRepository {
ScheduleResponseDto saveSchedule(Schedule schedule);
List<ScheduleResponseDto> findAllSchedules();
Schedule findScheduleByIdOrElseThrow(Long id);
int updateSchedule(Long id,String password, String name,String todo);
int deleteSchedule(Long id, String password);
}
package com.example.schedule.repository;
import com.example.schedule.dto.ScheduleResponseDto;
import com.example.schedule.entity.Schedule;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import org.springframework.web.server.ResponseStatusException;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Repository
public class ScheduleRepositoryImpl implements ScheduleRepository{
private final JdbcTemplate jdbcTemplate;
public ScheduleRepositoryImpl(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// repository) 일정 등록 메서드
@Override
public ScheduleResponseDto saveSchedule(Schedule schedule) {
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
simpleJdbcInsert.withTableName("schedule").usingGeneratedKeyColumns("id");
Map<String, Object> parameters = new HashMap<>();
parameters.put("name", schedule.getName());
parameters.put("password", schedule.getPassword());
parameters.put("todo", schedule.getTodo());
parameters.put("creationdate", schedule.getCreationdate());
parameters.put("modificationdate", schedule.getModificationdate());
Number key = simpleJdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
return new ScheduleResponseDto(key.longValue(), schedule.getName(),schedule.getTodo(),
schedule.getCreationdate(),schedule.getModificationdate());
}
// repository) 일정 목록 조회 메서드
@Override
public List<ScheduleResponseDto> findAllSchedules() {
return jdbcTemplate.query("select * from schedule order by modificationdate desc", scheduleRowMapper());
}
// repository) 일정 단건 조회 메서드
@Override
public Schedule findScheduleByIdOrElseThrow(Long id) {
List<Schedule> result = jdbcTemplate.query("select * from schedule where id = ?", scheduleRowMapperv2(), id);
return result.stream().findAny().orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Does not exists id = "+id));
}
// repository) 일정 수정 메서드
@Override
public int updateSchedule(Long id, String password, String name, String todo) {
return jdbcTemplate.update("update schedule set name=?, todo=?, modificationdate=? where id=?",name,todo, LocalDateTime.now(),id);
}
// repository) 일정 삭제 메서드
@Override
public int deleteSchedule(Long id, String password) {
return jdbcTemplate.update("delete from schedule where id=?",id);
}
// 각 행을 ScheduleResponseDto 타입으로 매핑 후 리스트로 반환해주는 메서드
private RowMapper<ScheduleResponseDto> scheduleRowMapper(){
return new RowMapper<ScheduleResponseDto>() {
@Override
public ScheduleResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
return new ScheduleResponseDto(rs.getLong("id"), rs.getString("name"),
rs.getString("todo"),
rs.getTimestamp("creationdate").toLocalDateTime(),
rs.getTimestamp("modificationdate").toLocalDateTime());
}
};
}
// 각 행을 Schedule 타입으로 매핑 후 리스트로 반환해주는 메서드
private RowMapper<Schedule> scheduleRowMapperv2() {
return new RowMapper<Schedule>() {
@Override
public Schedule mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Schedule(rs.getLong("id"),rs.getString("name"),rs.getString("password"),
rs.getString("todo"),rs.getTimestamp("creationdate").toLocalDateTime(),
rs.getTimestamp("modificationdate").toLocalDateTime());
}
};
}
}
package com.example.schedule.dto;
import com.example.schedule.entity.Schedule;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
@AllArgsConstructor
@Getter
public class ScheduleResponseDto {
private Long id;
private String name;
private String todo;
private LocalDateTime creationdate;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDateTime modificationdate;
public ScheduleResponseDto(Schedule schedule) {
this.id=schedule.getId();
this.name=schedule.getName();
this.todo=schedule.getTodo();
this.creationdate=schedule.getCreationdate();
this.modificationdate=schedule.getModificationdate();
}
}
package com.example.schedule.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
@AllArgsConstructor
@Getter
public class Schedule {
private Long id;
private String name;
private String password;
private String todo;
private LocalDateTime creationdate;
private LocalDateTime modificationdate;
public Schedule(String name, String password, String todo,
LocalDateTime creationdate,LocalDateTime modificationdate) {
this.name= name;
this.password = password;
this.todo = todo;
this.creationdate=creationdate;
this.modificationdate=modificationdate;
}
}
음 너무 코드만 많아서 좀 더러워보이긴 한데.. 막상 잘 읽어보면 잘 읽히리라 믿습니다.🙄 내일 과제 제출할 땐 주석처리 좀 해서 내는 걸로..
lv1을 다 만들고 나서 일정 등록하는 부분을 포스트맨으로 테스트를 해봤는데 406
Not Acceptable 에러가 떴다.
에러 코드: Resolved[org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation]
400번대 에러면 클라이언트 잘못인데 아무리 봐도 내가 뭔가 실수한 것 같지는 않아서 웹 서칭을 해보니 406 에러코드 설명은 서버가 요청의 사전 콘텐츠 협상 헤더에 정의된 허용 가능한 값 목록과 일치하는 응답을 생성 할 수 없으며 서버가 기본 표현을 제공하지 않음이라고 하고 @Getter를 안 붙이면 뜬다고 했다.
@Getter를 붙이니 해결이 되어 잘 작동한다.
해결은 했지만 왜 Getter를 사용하는 곳이 하나도 없다고 뜨는데 Getter를 붙이는지 이해가 안 되는 것 같아서 튜터님을 찾아가서 물어보았다. Jackson 라이브러리에서 리스폰스 응답객체를 확인하고 json으로 바꿔주는데 그 확인하는 방법이 getter를 통해서 확인하기 때문에 getter를 안 붙이게 되면 json형태로 되돌려 줄 수 없어서 406에러가 발생하는 것이라고 알려주셨다. 다음부터는 이런 에러를 마주쳐도 해결할 수 있을 것 같다.
과제를 하루 종일 하다 보니 좀 뭔가 기계가 된 느낌이랄까 성취의 뿌듯함을 느낄 새도 없이 계속해서 만들어내는 느낌이라 조금 답답한 느낌이다. 환기를 좀 시켜야 될 것 같기도 한데 또 숙련 시작이라니..😭 그래도 코드를 짜니까 시간은 빠르게 흐르는 것 같다. 요즘 계속 TIL이 밀리고 내 맘 같지 않네..