[Spring] Spring과 JPA를 사용해보기 - 학식 취향분석 프로그램 (1)
haksik-personalized
스프링 부트를 이용하여, 사용자 취향에 맞는 학식 메뉴를 추천해주는 간단한 프로그램을 구성해보았다.
이 프로젝트는 이전에 React와 코사인 유사도 알고리즘을 사용하여 만들었던 음식점 추천 시스템을 스프링 부트와 비슷하게 재구성하였다.
현재는 취향 분석의 여러개의 값이 존재하지 않아 평가된 메뉴 점수의 평균값만으로 취향을 분석하여 추천한다.
학식 메뉴를 제공하고, 사용자가 각 메뉴를 "좋아요", "보통이에요", "싫어요"로 평가할 수 있다. 사용자가 평가를 진행하면 각 메뉴에 대한 점수가 데이터베이스에 저장되고, 이후에 사용자에게 새로운 메뉴를 추천할 때 이 점수를 활용하게 되어있다.
(repository: https://github.com/WinterLimited/haksikbot-personalized)
GitHub - WinterLimited/haksikbot-personalized
Contribute to WinterLimited/haksikbot-personalized development by creating an account on GitHub.
github.com
시스템 작동 방식
사용자가 메뉴를 평가하면, 각 메뉴에 대한 점수가 데이터베이스에 저장된다.
(예를 들어, 사용자가 "닭갈비야채덮밥, 핫도그, 단무지"라는 메뉴를 "좋아요"로 평가하면, 각 메뉴에 5점이 부여되어 다음과 같은 방식으로 데이터베이스에 저장된다.)
메뉴: 닭갈비야채덮밥, 점수: 5
메뉴: 핫도그, 점수: 5
메뉴: 단무지, 점수: 5
유저의 개인적인 점수만을 계산하는 UserMenuScore 엔티티와 사용자 전원의 해당 메뉴에 대한 평가를 계산하는 Menu 엔티티가 존재하여 각각의 데이터베이스에 값을 수정/저장 하는 방식으로 프로그램을 구성하였습니다.
```java
public class UserMenuScore {
@Id
@Column(name = "id")
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user; // 유저
@ManyToOne
@JoinColumn(name = "menu_name")
private Menu menu; // 메뉴
@Column(name = "score")
private int score; // 점수
@Column(name = "count")
private int count; // 횟수
}
```java
public class Menu {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "menu_name")
private String menuName;
@Column(name = "score")
private int score;
@Column(name = "count")
private int count;
}
이후에 새로운 메뉴가 제공될 경우, 각 메뉴의 평균 점수를 계산하여 사용자의 취향에 얼마나 적합한지를 판단
-> 예외적으로 기존에 해당 메뉴에 대한 평가가 존재하지 않는 경우에는 사용자 전원이 내린 평가를 기반으로 계산하며, 해당 값도 존재하지 않는 경우에는 기본값인 3으로 분석을 진행
코드
이 시스템은 Spring Boot와 JPA를 사용하여 구현하였다. 사용자의 메뉴 점수를 계산하고 업데이트하는 두 가지 주요 기능은 다음 단계로 React.js와의 연동을 통해 프론트엔드를 구현할 예정이라 REST API를 사용하였다.
사용자의 메뉴 점수를 계산하는 API:
```java
@GetMapping("/api/{userId}/{menuName}")
public int getUserMenuScore(@RequestParam Long userId, @RequestParam String menuName) {
menuName = menuName.replaceAll(" ", "");
String[] menuNameArray = menuName.split(",");
int scoreSum = 0;
int scoreCount = 0;
for (String name : menuNameArray) {
if(userMenuScoreService.findByUserIdAndMenuMenuName(userId, name).isPresent()) {
scoreSum += userMenuScoreService.findByUserIdAndMenuMenuName(userId, name).get().getScore();
scoreCount++;
}
else {
scoreSum += menuService.findOne(name).get().getScore();
scoreCount++;
}
}
return scoreSum / scoreCount;
}
사용자의 메뉴 점수를 업데이트하는 API:
```java
@PostMapping("/api/menuscore")
public void updateUserMenuScore(@RequestParam Long userId, @RequestParam String menuName, @RequestParam int score) {
menuName = menuName.replaceAll(" ", "");
String[] menuNameArray = menuName.split(",");
for (String name : menuNameArray) {
menuService.updateMenuScore(name, score);
userMenuScoreService.updateMenuScore(userId, name, score);
}
}
느낀점
이번에 스프링을 통해 간단한 프로젝트를 구성해보는 것을 통해 기존에 Vanila PHP를 사용하여 유지보수성은 없고 어떤 방식으로 정리되지 않은 코드를 작성하던 방식에서 벗어나, 보다 체계적이고 유지보수가 용이한 스프링 프레임워크에 대해 학습하였다.
스프링 프레임워크는 여러 가지 장점들을 제공한다.
첫째) 의존성 주입을 통해 모듈 간의 결합도를 낮추어 코드의 유지보수성을 높인다.
둘째) AOP를 통해 반복적인 코드를 줄이고, 핵심 비즈니스 로직에만 집중할 수 있다.
셋째) 스프링은 웹 MVC, 보안, 트랜잭션 관리 등 여러 모듈을 제공하여 복잡한 웹 애플리케이션 개발을 보다 편리하게 만들어준다.
넷째) 스프링 부트를 통해 빠르게 웹 애플리케이션을 개발하고 배포할 수 있다.
이러한 스프링의 장점들을 수용하면서, 나를 더욱 발전시키기 위해 스프링 부트와 JPA를 사용한 이번 프로젝트를 진행하였다.
앞으로도 새로운 기술을 배우고 계속해서 발전해나가며, 보다 나은 코드를 작성하기 위해 노력해야겠다고 생각했다.