프로젝트 기능중 채팅방에서 유저가 아이템을 쓸 수 있는 기능이 있다.
유저가 아이템을 사용하기 위해선 아이템을 구매할 수 있어야 한다.
@GetMapping("/mypage/{item}")
@ApiOperation(value = "아이템 구매")
public HashMap<String, Object> buyItem(@PathVariable String item, @AuthenticationPrincipal UserDetailsImpl userDetails) {
User user = userDetails.getUser();
itemService.buyItem(item, user);
HashMap<String, Object> result = new HashMap<>();
result.put("result", "true");
return result;
컨트롤러에서 다음과같이 pathvariable로 item의 스트링 값을 받아온다.
public void buyItem(String item, User user) {
Item buyitem = itemRepository.findById(user.getItem().getId()).orElseThrow(
() -> new ItemNotFoundException("아이템이 없습니다")
);
switch (item) {
case "onlyMe":
buyitem.setOnlyMe(buyitem.getOnlyMe() + 1);
itemRepository.save(buyitem);
itemBuy(user, onlyMePrice, "나만 말하기");
break;
case "bigFont":
buyitem.setBigFont(buyitem.getBigFont() + 1);
itemRepository.save(buyitem);
itemBuy(user, bigFontPrice, "내글자 크게하기");
break;
case "myName":
buyitem.setMyName(buyitem.getMyName() + 1);
itemRepository.save(buyitem);
itemBuy(user, myNamePrice, "모두 내이름으로 바꾸기");
break;
case "papago":
buyitem.setPapago(buyitem.getPapago() + 1);
itemRepository.save(buyitem);
itemBuy(user, papagoPrice, "파파고 랜덤 번역");
break;
case "reverse":
buyitem.setReverse(buyitem.getReverse() + 1);
itemRepository.save(buyitem);
itemBuy(user, reversePrice, "글자 뒤집기");
break;
case "exBuy":
user.setEx(user.getEx()+exBuyPrice);
userRepository.save(user);
itemBuy(user, Long.valueOf(exBuyPrice),"경험치");
break;
}
}
각각의 케이스별로 아이템 구매시의 상황을 만들어 구매할 수 있게 해두었다.
//아이템 구매
private void itemBuy(User user, Long price, String item) {
if (user.getTotalPoint() >= price) {
user.setTotalPoint(user.getTotalPoint()-price);
userRepository.save(user);
Point point = new Point(item + " 구매", -price, user.getTotalPoint(), user);
pointRepository.save(point);
} else {
throw new LackPointException("보유한 포인트가 부족합니다");
}
}
@GetMapping("/chat/rooms/{item}")
@ApiOperation(value = "아이템 사용")
public HashMap<String, Object> userItem(@PathVariable String item, @AuthenticationPrincipal UserDetailsImpl userDetails) {
User user = userDetails.getUser();
itemService.useItem(item, user);
HashMap<String, Object> result = new HashMap<>();
result.put("result", "true");
return result;
}
//아이템 사용
public void useItem(String item, User user) {
Item useitem = itemRepository.findById(user.getItem().getId()).orElseThrow(
() -> new ItemNotFoundException("아이템이 없습니다")
);
switch (item) {
case "onlyMe":
if(useitem.getOnlyMe()>=1) {
useitem.setOnlyMe(useitem.getOnlyMe() - 1);
itemRepository.save(useitem);
}else {
throw new ItemNotFoundException("아이템이 없습니다");
}
break;
case "bigFont":
if(useitem.getBigFont()>=1) {
useitem.setBigFont(useitem.getBigFont() - 1);
itemRepository.save(useitem);
}else {
throw new ItemNotFoundException("아이템이 없습니다");
}
break;
case "myName":
if(useitem.getMyName()>=1) {
useitem.setMyName(useitem.getMyName() - 1);
itemRepository.save(useitem);
}else {
throw new ItemNotFoundException("아이템이 없습니다");
}
break;
case "papago":
if(useitem.getPapago()>=1) {
useitem.setPapago(useitem.getPapago() - 1);
itemRepository.save(useitem);
}else {
throw new ItemNotFoundException("아이템이 없습니다");
}
break;
case "reverse":
if(useitem.getReverse()>=1) {
useitem.setReverse(useitem.getReverse() - 1);
itemRepository.save(useitem);
}else {
throw new ItemNotFoundException("아이템이 없습니다");
}
break;
}
}
아이템 사용도 아이템 구매와 같은 방식으로 이루어진다.
코드에 반복되는 부분이 너무 많고 이것들을 획기적으로 줄일수있는 아이디어가 있을거라 생각된다.
우선 기능구현을 목표로 코드를 짜두었고 기능을 먼저 만든다음에 리팩터링을 할 계획이다.
다음으로는 아이템 기능 구현이다. 내가 맡은부분은 papago아이템과 reverse아이템이다
reverse아이템은 나 이외의 다른 유저들이 채팅을 칠 경우 단어가 뒤집혀서 나가게 된다.
papago아이템은 나 이외의 다른 유저들이 채팅을 칠 경우 단어가 11개국어중 랜덤으로 번역되어서 나가게 된다.

먼저 reverse 아이템의 경우
//단어 거꾸로 하기
public static String reverseWord(String word) {
StringBuffer sb = new StringBuffer(word);
return sb.reverse().toString();
}
간단하게 reverse메소드를 이용해서 만들어주었다.
그다음 papago아이템의 경우 네이버 papago의 오픈 api를 이용하여 만들었는데
//파파고
public static String papago(String string) throws IOException, NoSuchAlgorithmException {
String clientId = "";//애플리케이션 클라이언트 아이디값";
String clientSecret = "";//애플리케이션 클라이언트 시크릿값";
String apiURL = "https://openapi.naver.com/v1/papago/n2mt";
String text;
try {
text = URLEncoder.encode(string, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("인코딩 실패", e);
}
Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("X-Naver-Client-Id", clientId);
requestHeaders.put("X-Naver-Client-Secret", clientSecret);
String responseBody = post(apiURL, requestHeaders, text); //74개 짜르기
String text1 = responseBody.substring(responseBody.indexOf("translatedText")+17);
return text1.substring(0, text1.indexOf("engineType")-4); //뒤에 점찍히는거 뺄거면 -4 넣을거면 -3
}
private static String post(String apiUrl, Map<String, String> requestHeaders, String text) throws IOException, NoSuchAlgorithmException {
HttpURLConnection con = connect(apiUrl);
Random random = SecureRandom.getInstanceStrong();
int num = random.nextInt(11);
String postParams;
if (num == 1) {
postParams = "source=ko&target=en&text=" + text;
} else if(num==2) {
postParams = "source=ko&target=ja&text=" + text;
}else if(num==3) {
postParams = "source=ko&target=zh-CN&text=" + text;
}else if(num==4) {
postParams = "source=ko&target=vi&text=" + text;
}else if(num==5) {
postParams = "source=ko&target=id&text=" + text;
}else if(num==6) {
postParams = "source=ko&target=th&text=" + text;
}else if(num==7) {
postParams = "source=ko&target=de&text=" + text;
}else if(num==8) {
postParams = "source=ko&target=ru&text=" + text;
}else if(num==9) {
postParams = "source=ko&target=es&text=" + text;
}else if(num==10) {
postParams = "source=ko&target=it&text=" + text;
}else{
postParams = "source=ko&target=fr&text=" + text;
}
// postParams = "source=ko&target=en&text=" + text; //원본언어: 한국어 (ko) -> 목적언어: 영어 (en)
try {
con.setRequestMethod("POST");
for(Map.Entry<String, String> header :requestHeaders.entrySet()) {
con.setRequestProperty(header.getKey(), header.getValue());
}
con.setDoOutput(true);
try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
wr.write(postParams.getBytes());
wr.flush();
}
int responseCode = con.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 응답
return readBody(con.getInputStream());
} else { // 에러 응답
return readBody(con.getErrorStream());
}
} catch (IOException e) {
throw new RuntimeException("API 요청과 응답 실패", e);
} finally {
con.disconnect();
}
}
private static HttpURLConnection connect(String apiUrl){
try {
URL url = new URL(apiUrl);
return (HttpURLConnection)url.openConnection();
} catch (MalformedURLException e) {
throw new RuntimeException("API URL이 잘못되었습니다. : " + apiUrl, e);
} catch (IOException e) {
throw new RuntimeException("연결이 실패했습니다. : " + apiUrl, e);
}
}
private static String readBody(InputStream body){
InputStreamReader streamReader = new InputStreamReader(body);
try (BufferedReader lineReader = new BufferedReader(streamReader)) {
StringBuilder responseBody = new StringBuilder();
String line;
while ((line = lineReader.readLine()) != null) {
responseBody.append(line);
}
return responseBody.toString();
} catch (IOException e) {
throw new RuntimeException("API 응답을 읽는데 실패했습니다.", e);
}
}
파파고 api코드에 대한 정확한 이해는 하지 못하였으나 기능을 만들기 위해 사용하였다.
String post메소드에서 난수를 생성하여 랜덤으로 번역되서 나가게 설정해두었다 위 코드의 경우도 리팩터링을 통해
충분히 코드를 바꿀 수 있을거라 생각이 든다
'공부기록 > 자바 스프링' 카테고리의 다른 글
| JPA 연관관계 (0) | 2022.04.17 |
|---|---|
| 스프링 아이템기능 리팩터링 (0) | 2022.03.19 |
| 스프링 룰렛기능 만들기 (가챠시스템), 자바 난수 설정, 확률설정 (0) | 2022.03.09 |
| 스프링 배팅시스템 만들기 (트위치 배팅시스템 참고) (0) | 2022.03.08 |
| 스프링부트 JPA 중복검색 해결 <트러블 슈팅> (0) | 2022.03.07 |