이전에 자바로 만들었던 notice 프로젝트를 이용했다.
Domain
Notice
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "notice")
public class Notice {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "notice_id")
private int id;
@Column(name = "user_id")
private String userID;
private String title;
private String content;
private String write_date;
}
- 위는 자바 코드다
- 자바에서는 getter / setter를 위해 lombok을 이용한다.
@Entity
class Notice (
@Column(name = "user_id")
val userID: String,
var title: String,
var content: String,
val write_date: String,
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int = 0,
)
- 아래는 코틀린 코드다.
- 코틀린에서의 객체는 getter / setter를 자동으로 제공하므로 별도의 getter / setter 설정이 필요없다.
- 여기서 notice 객체는 이후에 업데이트 될 경우 title과 content 내용이 바뀔 수 있으므로 var 타입으로 선언한다.
- 자바의 경우 기본키는 인자로 받지 않는다.
- 코틀린의 경우 기본키도 인자로 받아진다.
- 코틀린에서는 기본 키에 디폴트 값을 정해주고, 디폴트 값을 지정한 경우 맨 아래 적는 것이 관례라 한다.
DTO
NoticeWriteDTO
@Getter
@Setter
public class NoticeWriteDTO {
private String email;
private String title;
private String content;
}
class NoticeWriteDTO (
val email: String,
val title: String,
val content: String
)
- 위가 자바, 아래가 코틀린 코드다.
- Domain과 마찬가지로 자바에는 getter / setter 어노테이션이 필요하지만 코틀린은 필요없다.
- DTO는 자바와 코틀린의 문법에만 맞춘다면 크게 변경할 점은 없다.
NoticeUpdateDTO
@Getter
@Setter
public class NoticeUpdateDTO {
private int id;
private String title;
private String content;
}
class NoticeUpdateDTO (
val id: Int,
val title: String,
val content: String
)
Repository
NoticeRepository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
void deleteById(int id);
Notice findById(int id);
List<Notice> findAllByOrderByIdDesc();
List<Notice> findAllByUserIDOrderByIdDesc(String id);
List<Notice> findAllByTitleContainingOrderByIdDesc(String title);
}
interface NoticeRepository : JpaRepository<Notice, Long> {
fun deleteById(id: Int)
fun findById(id: Int): Notice
fun findAllByOrderByIdDesc(): List<Notice>?
fun findAllByUserIDOrderByIdDesc(id: String): List<Notice>?
fun findAllByTitleContainingOrderByIdDesc(title: String): List<Notice>?
}
- 위는 자바, 아래는 코틀린 코드다.
- 자바에서는 null 안정성을 지원하지 않기 때문에 코틀린으로 코드를 변경할 때 이 부분을 신경써야 한다.
- 반환형 지정 시 null이 가능한지 판단해야한다.
- 단순 조회같은 경우는 존재하지 않을 수 있기 때문에 ?로 null이 가능함을 명시해야하고,
- 서비스단에서 반환 값을 이용해 객체의 프로퍼티를 사용한다면 null이 가능해서는 안된다.
Service
NoticeService
@Service
@Transactional
public class NoticeService {
private NoticeRepository noticeRepository;
@Autowired
public NoticeService(NoticeRepository noticeRepository){
this.noticeRepository = noticeRepository;
}
public void addNotice(NoticeWriteDTO noticeWriteDTO){
Notice newNotice = new Notice();
newNotice.setUserID(noticeWriteDTO.getUserID());
newNotice.setTitle(noticeWriteDTO.getTitle());
newNotice.setContent(noticeWriteDTO.getContent());
newNotice.setWrite_date(LocalDate.now());
noticeRepository.save(newNotice);
}
public void updateNotice(NoticeUpdateDTO noticeUpdateDTO){
Notice newNotice = new Notice();
newNotice.setId(noticeUpdateDTO.getId());
newNotice.setUserID(noticeRepository.findById(noticeUpdateDTO.getId()).getUserID());
newNotice.setTitle(noticeUpdateDTO.getTitle());
newNotice.setContent(noticeUpdateDTO.getContent());
newNotice.setWrite_date(noticeRepository.findById(noticeUpdateDTO.getId()).getWrite_date());
noticeRepository.save(newNotice);
}
public List<Notice> allNotice(){
return noticeRepository.findAllByOrderByIdDesc();
}
public Notice noticeContent(int id){
return noticeRepository.findById(id);
}
public List<Notice> titleNotice(String title){ return noticeRepository.findAllByTitleContainingOrderByIdDesc(title); }
public List<Notice> writerNotice(String id){
return noticeRepository.findAllByUserIDOrderByIdDesc(id);
}
public void deleteNotice(int id) { noticeRepository.deleteById(id);}
}
@Service
@Transactional
class NoticeService (val noticeRepository: NoticeRepository){
// notice 추가
@Transactional
fun addNotice(noticeWriteDTO: NoticeWriteDTO) {
val email = noticeWriteDTO.email
val title = noticeWriteDTO.title
val content = noticeWriteDTO.content
val notice = Notice(email, title, content, LocalDate.now().toString())
noticeRepository.save(notice)
// 레포지토리는 변경할 수 없어야 함 -> val 안하면 오류
}
// notice 수정
@Transactional
fun updateNotice(noticeUpdateDTO: NoticeUpdateDTO){
val id = noticeUpdateDTO.id
val notice = noticeRepository.findById(id)
notice.title = noticeUpdateDTO.title
notice.content = noticeUpdateDTO.content
noticeRepository.save(notice)
}
// notice 전체 조회
fun allNotice(): List<Notice>? {
return noticeRepository.findAllByOrderByIdDesc()
}
// notice 상세 내용 조회
fun noticeContent(id: Int): Notice {
return noticeRepository.findById(id)
}
// notice 제목 검색
fun titleNotice(title: String): List<Notice>? {
return noticeRepository.findAllByTitleContainingOrderByIdDesc(title)
}
// notice 작성자 검색
fun writerNotice(id: String): List<Notice>? {
return noticeRepository.findAllByUserIDOrderByIdDesc(id)
}
// notice 삭제
@Transactional
fun deleteNotice(id: Int) {
noticeRepository.deleteById(id)
}
}
- 위는 자바, 아래는 코틀린 코드다.
- 자바에서 service 코드는 repository 의존성 주입을 해야한다.
- 코틀린에서는 이를 클래스의 생성자로 넣어준다..
- 코틀린의 장점인 getter / setter가 자동으로 생성되므로 이를 처리하는 부분에서 코드의 길이가 줄어든다.
Controller
NoticeController
@RestController
@RequestMapping("/notice")
public class NoticeController {
@Autowired
private NoticeService noticeService;
public NoticeController(NoticeService noticeService) {
this.noticeService = noticeService;
}
// 공지사항 전체 조회
@GetMapping("all")
public ResponseEntity<List<Notice>> allSearchNotice(){
return ResponseEntity.ok().body(noticeService.allNotice());
}
// 공지사항 내용 상세 조회
@GetMapping("{id}")
public ResponseEntity<Notice> noticeContent(@PathVariable int id){
return ResponseEntity.ok().body(noticeService.noticeContent(id));
}
// 공지사항 제목 검색
@GetMapping("/title/{title}")
public ResponseEntity<List<Notice>> titleNotice(@PathVariable String title){
return ResponseEntity.ok().body(noticeService.titleNotice(title));
}
// 공지사항 작성자 검색
@GetMapping("writer/{id}")
public ResponseEntity<List<Notice>> writerNotice(@PathVariable String id){
return ResponseEntity.ok().body(noticeService.writerNotice(id));
}
// 공지사항 작성
@PostMapping(value = "/write", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> addNotice(@RequestBody NoticeWriteDTO noticeWriteDTO){
noticeService.addNotice(noticeWriteDTO);
return ResponseEntity.ok().body("success");
}
// 공지사항 수정
@PostMapping("/update")
public ResponseEntity<String> updateNotice(@RequestBody NoticeUpdateDTO noticeUpdateDTO){
noticeService.updateNotice(noticeUpdateDTO);
return ResponseEntity.ok().body("success");
}
// 공지사항 삭제
@GetMapping("delete/{id}")
public ResponseEntity<String> deleteNotice(@PathVariable int id){
noticeService.deleteNotice(id);
return ResponseEntity.ok().body("success");
}
}
@RestController
@RequestMapping("/notice")
class NoticeController (private val noticeService: NoticeService){
@PostMapping("/write")
fun addNotice(@RequestBody noticeWriteDTO: NoticeWriteDTO): ResponseEntity<String> {
noticeService.addNotice(noticeWriteDTO)
return ResponseEntity.ok().body("success")
}
@GetMapping("/all")
fun allSearchNotice(): ResponseEntity<List<Notice>> {
return ResponseEntity.ok().body(noticeService.allNotice())
}
@GetMapping("/{id}")
fun noticeContent(@PathVariable id: Int): ResponseEntity<Notice> {
return ResponseEntity.ok().body(noticeService.noticeContent(id))
}
@GetMapping("/title/{title}")
fun titleNotice(@PathVariable title: String): ResponseEntity<List<Notice>> {
return ResponseEntity.ok().body(noticeService.titleNotice(title))
}
@GetMapping("/writer/{id}")
fun writerNotice(@PathVariable id: String): ResponseEntity<List<Notice>> {
return ResponseEntity.ok().body(noticeService.writerNotice(id))
}
@DeleteMapping("/delete/{id}")
fun deleteNotice(@PathVariable id: Int): ResponseEntity<String>{
noticeService.deleteNotice(id)
return ResponseEntity.ok().body("success")
}
@PostMapping("/update")
fun updateNotice(@RequestBody noticeUpdateDTO: NoticeUpdateDTO): ResponseEntity<String> {
noticeService.updateNotice(noticeUpdateDTO)
return ResponseEntity.ok().body("success")
}
}
- 컨트롤러에서 변경 되는 점 또한 문법 차이다.
- 어노테이션의 경우 변경되는 것이 없다.
- 의존성 주입 또한 service에서와 같이 클래스 생성자 부분에 작성한다.
Test
>> Test는 Postman으로 진행하였다.
/notice/write - addNotice
- 공지사항 추가가 제대로 되어 success가 반환된 것을 알 수 있다.
/notice/all - allSearchNotice
- 앞서 추가했던 notice들이 모두 반환된 것을 볼 수 있다.
/notice/5 - noticeContent
- 해당 번호의 notice의 전체 내용을 가져오는 것을 확인할 수 있다.
/notice/title/today - titleNotice
- 제목 검색어를 포함하는 notice들을 모두 반환한다.
/notice/writer/abbiddo - writerNotice
- 작성자가 게시한 notice들을 반환한다.
/notice/update - updateNotice
- update에 성공해서 success를 반환한다.
- 내용이 잘 업데이트 된 것도 확인할 수 있다.
/notice/delete/5 - deleteNotice
- delete에 성공해서 success를 반환한다.
- 내용이 잘 삭제된 것도 확인할 수 있다.
'Backend > Server' 카테고리의 다른 글
[Gradle] Unresolved reference: (1) | 2024.02.13 |
---|---|
[Spring] MVC 모델 (0) | 2023.08.04 |
[Spring] API 작성하기 (0) | 2023.08.02 |
[Flask] 질문 목록과 상세 기능 (0) | 2023.07.31 |
[Flask] 데이터 처리하기 (DB) (2) (0) | 2023.07.31 |