Light Blue Pointer
본문 바로가기
Developing/개발일지

2024-01-14, Today I Learned

by Greedy 2024. 1. 15.

오늘 한 일

1. 나가기 기능 개발

2. 글 작성페이지 프론트 다듬기

3. 글 상세페이지 만들기 시작 (2024-01-15에 완료함)

 

1. 나가기 기능

나가기 기능 개발 완료!

Controller

//나가기 기능
    @DeleteMapping("/posts/exit")
    public ApiResponse<Void> exit(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @Valid @RequestBody PostIdRequest postIdReq
    ) {
        postService.exit(postIdReq, userDetails.getUser());
        return new ApiResponse<>(HttpStatus.OK.value(), "글에서 나가기 되었습니다.");
    }

Service

@Override
    public void exit(PostIdRequest postIdReq, User user) {
        Post post = getPostById(postIdReq.postId());
        UserPost userPost = userPostRepository.findByPostAndUserAndRoleEquals(post, user, UserPostRole.PARTICIPANT).orElseThrow(()->
            new GlobalException(PostErrorCode.FORBIDDEN_ACCESS_PARTICIPANT)
        );
        menuRepository.deleteAll(getUserMenus(user,post));
        userPostRepository.delete(userPost);
    }

UserPostRepository

Optional<UserPost> findByPostAndUserAndRoleEquals(Post post, User user, UserPostRole role);

ErrorCode를 정의하려는데 FORBIDDEN_ACCESS 밑에다가 FORBIDDEN_ACCESS_PARTICIPANT 만들려니까 뭔가 분류가 안 맞는거 같아서

FORBIDDEN_ACCESS를 FORBIDDEN_ACCESS_HOST로 변경함!

package com.moayo.moayoeats.backend.domain.userpost.exception;

import com.moayo.moayoeats.backend.global.exception.ErrorCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum UserPostErrorCode implements ErrorCode {

    // 404
    NOT_FOUND_USERPOST(HttpStatus.NOT_FOUND.value(), "해당 글과 사용자와의 관계를 찾을 수 없습니다."),
    NOT_FOUND_HOST(HttpStatus.NOT_FOUND.value(), "작성자를 찾을 수 없습니다.");

    private final int httpStatus;
    private final String message;
}

이어서

어제 했던 글 작성 페이지 기능 몇가지 더 하고 마감해서 pr함!

오늘 보니 카테고리가 PostRequest에서는 안 바뀌어 있길래 CategoryEnum 대신 String으로 바꾸고 @Category로 validation 해줌

public record PostRequest(

    @NotBlank String address, 
    @NotBlank String store, 
    @NotNull Integer minPrice,
    @NotNull Integer deliveryCost,

    @NotNull @Max(59) Integer deadlineMins, 
    @NotNull @Max(3) Integer deadlineHours,
    @Category String category

) {

}

 

 

 2. 글 작성페이지 프론트 다듬기

html파일에서 쓸모있는 부분만 남겨봄

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
        name="viewport">
  <title>글 작성하기</title>
  <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
  <script src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpClientId=sa2ld1fdvv&submodules=geocoder"
          type="text/javascript"></script>
</head>
<body>
<div class="card-body">
  <input class="form-control" id="store" placeholder="가게" type="text">
  <input class="form-control" id="minPrice" placeholder="최소주문금액" type="text">
  <input class="form-control" id="deliveryCost" placeholder="배달비" type="text">
  <input class="form-control" id="deadlineMins" placeholder="마감시간 시간" type="text">
  <input class="form-control" id="deadlineHours" placeholder="마감시간 분" type="text">
</div>
<button class="btn btn-outline-secondary" onclick="sendData()" type="button">작성 완료</button>

<div id="map" style="width:100%; height:800px;"></div>

<script th:inline="javascript">
  var map = new naver.maps.Map("map", {
        center: new naver.maps.LatLng(37.5666103, 126.9783882),
        zoom: 16
      }),
      infoWindow = null;

  var latlng;

  function initGeocoder() {
    latlng = map.getCenter();

    infoWindow = new naver.maps.InfoWindow({
      content: ''
    });

    map.addListener('click', function (e) {
      latlng = e.coord;

      infoWindow.setContent([
        '<div style="padding:10px;width:380px;font-size:14px;line-height:20px;">',
        '<div> ' + ' ' + '</div>',
        '</div>'
      ].join(''));
      infoWindow.open(map, latlng);
    });
  }

  naver.maps.onJSContentLoaded = initGeocoder;

  function sendData() {

    let address = latlng.toString();
    let store = $('#store').val();
    let minPrice = $('#minPrice').val();
    let deliveryCost = $('#deliveryCost').val();
    let deadlineMins = $('#deadlineMins').val();
    let deadlineHours = $('#deadlineHours').val();
    $.ajax({
      type: 'POST',
      url: "/api/v1/test/posts",
      dataType: "json",
      contentType: 'application/json',
      data: JSON.stringify({
        address: address,
        store: store,
        minPrice: minPrice,
        deliveryCost: deliveryCost,
        deadlineMins: deadlineMins,
        deadlineHours: deadlineHours
      }),
      success: function (response) {
        console.log('Success:', response);
      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }
</script>

</body>
</html>

address로 받아온거 위도랑 경도로 나눠서 넣어봄

 

{status: 201, message: '글을 생성했습니다.', data: null}

 

//Test
    public void createPostTest(PostRequest postReq){
        //set fake user
        Long l = 1L;
        User user = userRepository.findById(l).orElse(null);

        //set deadline to hours and mins after now
        LocalDateTime deadline = LocalDateTime.now().plusMinutes(postReq.deadlineMins()).plusHours(postReq.deadlineHours());
        String address = postReq.address();
        address = address.replace("lat:","");
        address = address.replace("lng:","");
        String [] location = address.split(",");
        double latitude = Double.parseDouble(location[0]);
        double longitude = Double.parseDouble(location[1]);

        //Build new post with the post request dto
        Post post = Post.builder()
            .latitude(latitude)
            .longitude(longitude)
            .store(postReq.store())
            .deliveryCost(postReq.deliveryCost())
            .minPrice(postReq.minPrice())
            .deadline(deadline)
            .category(postReq.category())
            .postStatus(PostStatusEnum.OPEN)
            .build();

        //save the post
        postRepository.save(post);

        //Build new relation between the post and the user
        UserPost userpost = UserPost.builder()
            .user(user)
            .post(post)
            .role(UserPostRole.HOST)
            .build();

        //save the relation
        userPostRepository.save(userpost);
    }

java.lang.NumberFormatException: For input string: "(37.5654367”

(제거하는거 까먹음…

괄호도 제거해줌

 

address = address.replace("(lat:","");
        address = address.replace("lng:","");
        address = address.replace("):","");

 

🚩문제 : 에러 발생

브라우저 콘솔에 이렇게 뜸

jquery-3.6.4.min.js:2

   POST <http://localhost:8080/api/v1/test/posts> 403 (Forbidden)

send @ jquery-3.6.4.min.js:2 ajax @ jquery-3.6.4.min.js:2 sendData @ createpost:62 onclick @ createpost:20 createpost:79 Error: {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}

왜이러세요

스프링 콘솔에도 에러뜸

java.lang.NumberFormatException: For input string: "126.9726375)" at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054) ~[na:na] at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) ~[na:na] at java.base/java.lang.Double.parseDouble(Double.java:651) ~[na:na] at com.moayo.moayoeats.backend.domain.post.service.impl.PostServiceImpl.createPostTest(PostServiceImpl.java:216) ~[main/:na] at

126.9726375 이거 Double로 왜 못 만들어?

FloatingDecimal→ 이건 뭐야 Float로 해야한다고?

 

찾아보니 parseDouble을 하면 E14이런식의 지수표현으로 들어가서

NumberFormat을 써야한다고 함

근데 이건 출력 예쁘게 하는 법이잖아

NumberFormat format = NumberFormat.getInstance();
format.setGroupingUsed(false);

System.out.println(format.format(dNum1);

 

 

Double.valueOf 써봄

double latitude = Double.parseDouble(location[0]);
double longitude = Double.parseDouble(location[1]);

double latitude = Double.valueOf(location[0]);
double longitude = Double.valueOf(location[1]);

java.lang.NumberFormatException: For input string: "126.9788817)”

address = address.replace("):","");

다시보니 괄호 제거를 잘못함

⛳해결1: 괄호 제거함

address = address.replace(")","");

java.sql.SQLIntegrityConstraintViolationException: Column 'address' cannot be null

@Column(nullable = true)
    private String address;

    @Column(nullable = true)
    private Double latitude;

    @Column(nullable = true)
    private Double longitude;

이렇게 넣어줌

해결이 안 됨

java.sql.SQLIntegrityConstraintViolationException: Column 'address' cannot be null

⛳해결2: address field 그냥 넣어줌

//set deadline to hours and mins after now
        LocalDateTime deadline = LocalDateTime.now().plusMinutes(postReq.deadlineMins()).plusHours(postReq.deadlineHours());
        String address = postReq.address();
        address = address.replace("(lat:","");
        address = address.replace("lng:","");
        address = address.replace(")","");
        String [] location = address.split(",");
        double latitude = Double.valueOf(location[0]);
        double longitude = Double.valueOf(location[1]);

        //Build new post with the post request dto
        Post post = Post.builder()
            .address(address)
            .latitude(latitude)
            .longitude(longitude)
            .store(postReq.store())
            .deliveryCost(postReq.deliveryCost())
            .minPrice(postReq.minPrice())
            .deadline(deadline)
            .category(postReq.category())
            .postStatus(PostStatusEnum.OPEN)
            .build();

address 걍 넣어줌

{status: 201, message: '글을 생성했습니다.', data: null}

됐다!!

db에 잘 들어감!!

2,"37.570301,126.9804481",,2024-01-14 16:38:28.976549,1,1,OPEN,1,,37.570301,126.9804481

 

 

 

🚀issue: 좌표값 db에서 받아와서 화면에 마커로 출력하기

이제 db에서 좌표값 꺼내서 출력해봄!

글 상세페이지에서 조회를 시도해본다!

//Test
    @GetMapping("/test/posts/{postId}")
    public ApiResponse<DetailedPostResponse> getPostTest(
        @PathVariable(name = "postId") Long postId
    ) {
        return new ApiResponse<>(HttpStatus.OK.value(), "글 상세페이지 조회에 성공했습니다.",
            postService.getPostTest(postId));
    }
@Override
    public DetailedPostResponse getPostTest(Long postId) {
        Post post = getPostById(postId);
        List<UserPost> userPosts = getUserPostsByPost(post);

        return DetailedPostResponse.builder()
            .longitude(post.getLongitude())
            .latitude(post.getLatitude())
            .address(post.getAddress())
            .store(post.getStore())
            .minPrice(post.getMinPrice())
            .deliveryCost(post.getDeliveryCost())
            .menus(getNickMenus(userPosts))
            .sumPrice(getSumPrice(userPosts, post))
            .deadline(getDeadline(post))
            .build();
    }

근데 고민에 빠짐

문제 : 만약에 이렇게 해서 {postId}를 받아온다고 침 그러면

그걸 호출하는 html로는 어떻게 전달하지??

→ (spoiler alert🚨)ModelAndView로 다음날 해결함

 

$.ajax({
  type: "GET",
  url: "<http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99>",
  data: {},
  success: function (response) {
    let mise_list = response["RealtimeCityAir"]["row"];
    for (let i = 0; i < mise_list.length; i++) {
      let mise = mise_list[i];
      let gu_name = mise["MSRSTE_NM"];
      let gu_mise = mise["IDEX_MVL"];
      console.log(gu_name, gu_mise);
    }
  },
});

이거 보고 일단 이런식으로 해봄

<script th:inline="javascript">
  var latitude;
  var longitude;

  var map = new naver.maps.Map('map', {
    center: new naver.maps.LatLng(latitude, longitude),
    zoom: 15
  });

  var marker = new naver.maps.Marker({
    position: new naver.maps.LatLng(latitude, longitude),
    map: map
  });

  function getData() {

    let address = latlng.toString();
    let store = $('#store').val();
    let minPrice = $('#minPrice').val();
    let deliveryCost = $('#deliveryCost').val();
    let deadlineMins = $('#deadlineMins').val();
    let deadlineHours = $('#deadlineHours').val();

    $.ajax({
      type: 'GET',
      url: `/api/v1/test/posts/1`, //-> 이부분도 좀 큰일이긴 함 어떻게 받아올지?
      dataType: "json",
      contentType: 'application/json',
      data: {},
      success: function (response) {
        console.log('Success:', response);
        latitude = response["latitude"];
        longitude = response["latitude"];
      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

</script>

latitude, longitude 전역변수 선언해준 다음에 response에서 뽑아와봄

실행시켜봄

오 근데 큰일남 ㅋㅋㅋㅋㅋㅋ

🚩문제: 마커가 망망대해에 찍힘

망망대해에 떠있는 마커 뭐임

latitude = response["latitude"];
 longitude = response["latitude"];

내가 longitude 자리에 latitude를 넣어줌

고침

success: function (response) {
        console.log('Success:', response);
        latitude = response["latitude"];
        longitude = response["longitude"];
      },

아 테스트를 postId=1로 하고있었는데

그건 db에 longitude랑 latitude가 둘다 null인거임

postId = 5로 진행해봄

	type: 'GET',
      url: `/api/v1/test/posts/5`,
      dataType: "json",
      contentType: 'application/json',

아직도 망망대해임

center: new naver.maps.LatLng(35.1769695,129.1049723),

이거 리터럴로 넣어서 하면 부산이 잘만 나옴…

 

latitude랑 longitude의 형식이 잘못되어서 읽지를 못하는걸까?

Double이 아니고 float였나?

https://navermaps.github.io/maps.js.ncp/docs/naver.maps.LatLng.html

공식문서를 읽어봅니다

lat와 lng의 타입은 number라고 함

number

정수와 실수를 포함하는 숫자(Number)를 표현합니다. Type:number

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number

Number

Number values represent floating-point numbers like 37 or -9.25.

The Number constructor contains constants and methods for working with numbers. Values of other types can be converted to numbers using the Number() function.

Description

Numbers are most commonly expressed in literal forms like 255 or 3.14159. The lexical grammar contains a more detailed reference.

JSCopy to Clipboard

255; // two-hundred and fifty-five
255.0; // same number
255 === 255.0; // true
255 === 0xff; // true (hexadecimal notation)
255 === 0b11111111; // true (binary notation)
255 === 0.255e3; // true (decimal exponential notation)

오… Javascript에는 number type이 있나봄

 

아 그냥 String을 한번 넣어봄!

<script th:inline="javascript">
  var latitude;
  var longitude;
  var address;

  var map = new naver.maps.Map('map', {
    center: new naver.maps.LatLng(address),
    zoom: 15
  });

  var marker = new naver.maps.Marker({
    position: new naver.maps.LatLng(address),
    map: map
  });

  function getData() {

    $.ajax({
      type: 'GET',
      url: `/api/v1/test/posts/5`,
      dataType: "json",
      contentType: 'application/json',
      data: {},
      success: function (response) {
        console.log('Success:', response);
        latitude = response["latitude"];
        longitude = response["longitude"];
        address = response["address"];
      },

될리가 없죠

근데 null일때 Double일 때 String일 때 다 망망대해 뜨는거 보니까

지금 문제가 Double을 못 읽어서 그런거라는게 좀 더 명확해지는거 같다

var latitude;
  var longitude;

  var map = new naver.maps.Map('map', {
    center: new naver.maps.LatLng(latitude, longitude),
    zoom: 15
  });

  var marker = new naver.maps.Marker({
    position: new naver.maps.LatLng(latitude, longitude),
    map: map
  });

다시 여기로 돌아옴

근데 문제가 Double을 못 읽은게 아니라 데이터가 전역변수에 안 들어가서 저런 결과가 나오는 거라면?

개발자도구를 켜봄

아무것도 안 뜸

아 근데 생각난건데

console.log('Success:', response);
        latitude = response["latitude"];
        longitude = response["longitude"];

지금 response가 ApiResponse(내가 정의한 객체)라서 그 안에서 data에 또 들어가서 값을 읽어야 할 거 같음!

아 아까 왜 블로그 게시글에서 본 거에서 [][]이게 이차원 배열처럼 두개 써있나 했다

이런 경우에서 계층구조 읽으려고 그렇게 쓴 거였나봄

$.ajax({
      type: 'GET',
      url: `/api/v1/test/posts/5`,
      dataType: "json",
      contentType: 'application/json',
      data: {},
      success: function (response) {
        console.log('Success:', response["message"]);
        latitude = response["data"]["latitude"];
        longitude = response["data"]["longitude"];
      },
      error: function (error) {
        console.error('Error:', error);
      }
    });

이렇게 바꿔봄

여전히 안 된다!!!

걍 데이터를 저런 형식으로 읽어오는게 아닌거같음 메시지도 안 나옴

콘솔 로그 바꿔서 테스트해봄

success: function (response) {
        console.log('Success:', response["message"]);

success: function (response) {
        console.log('Success:');

아 ㅋㅋㅋㅋㅋ 바본가

@GetMapping("/test/readpost/{postId}")
    public String readpostPage(

    ){
        return "domain/post/readpost";
    }

컨트롤러에 path variable을 안 달면 그냥 저 {postId}까지가 문자 그대로 주소가 되는거잖아 ㅜ 아 근데 아닌가 어떻게 저 html파일은 잘 찾아내서 들고왔는데?

@GetMapping("/test/readpost/{postId}")
    public String readpostPage(
        @PathVariable(name = "postId") Long postId
    ){
        return "domain/post/readpost";
    }

아무튼 이렇게 해봅니다

html파일을 똑바로 들고온거보면 저걸 실행하는데는 아무 문제가 없었을듯

응 바꾸나마나 아무 차이가 없었음~

망망대해임 아직도

아 뭐가 문제일까 한참 멍때려보니

<script th:inline="javascript">
  var latitude;
  var longitude;

  var map = new naver.maps.Map('map', {
    center: new naver.maps.LatLng(latitude, longitude),
    zoom: 15
  });

  var marker = new naver.maps.Marker({
    position: new naver.maps.LatLng(latitude, longitude),
    map: map
  });

  function getData() {

    $.ajax({
      type: 'GET',
      url: `/api/v1/test/posts/5`,
      dataType: "json",
      contentType: 'application/json',
      data: {},
      success: function (response) {
        console.log('Success:');
        latitude = response["data"]["latitude"];
        longitude = response["data"]["longitude"];
      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

</script>

저 함수가 아예 실행이 안 되고 있음!

⛳해결중: $( document ).ready 메서드 사용해서 페이지 로딩과 동시에 ajax GET메서드 실행되게 함

document.ready함수던가 그런걸 써줘야 할 거 같음

$( document ).ready(function() {
    getData();
  });

이거 추가해봄!

오 이제 실행되나봄 성공메시지는 출력이 됨!

 

 

망망대해와 함께 ㅋㅋㅋㅋㅋㅋ

아무튼 일보 전진이다!!

function (response)

여기서 값을 꺼내는 문법을 모르겠어서 찾아봄

 

https://developer.mozilla.org/en-US/docs/Web/API/Response

Response.json()
Returns a new Response object for returning the provided JSON encoded data.

https://developer.mozilla.org/en-US/docs/Web/API/Response

success: function (response) {
        console.log('Success:',response);
        res = response.json();
        latitude = res.data.latitude;
        longitude = res.data.longitude;
      },

한번 이렇게 해봄

Success: {status: 200, message: '글 상세페이지 조회에 성공했습니다.', data: {…}} 1:42 Uncaught TypeError: response.json is not a function at Object.success (1:42:24) at c (jquery-3.6.4.min.js:2:28447) at Object.fireWith [as resolveWith] (jquery-3.6.4.min.js:2:29192) at l (jquery-3.6.4.min.js:2:80176) at XMLHttpRequest.<anonymous> (jquery-3.6.4.min.js:2:82630)

이렇게 뜸

$.ajax({
      type: 'GET',
      url: `/api/v1/test/posts/5`,
      dataType: "json",
      contentType: 'application/json',
      data: {},
      success: function (response) {
        console.log('Success:',response);
        res = response.data;
        latitude = res.latitude;
        longitude = res.longitude;
      },
      error: function (error) {
        console.error('Error:', error);
      }
    });

이렇게 해봄

 

아무것도 안 떠요~

https://www.tutorialspoint.com/prototype/prototype_ajax_response.htm

success: function (response) {
        console.log('Success:',response);
        latitude =$('latitude');
        longitude = $('longitude');
      },

이렇게 해봄

Success:

  1. {status: 200, message: '글 상세페이지 조회에 성공했습니다.', data: {…}}
    1. data:
      1. address: "35.1769695,129.1049723"
      2. deadline: "2024-01-14T22:18:06"
      3. deliveryCost: 1
      4. latitude: 35.1769695
      5. longitude: 129.1049723
      6. menus: [{…}]
      7. minPrice: 1
      8. store: "123"
      9. sumPrice: 0
      10. [[Prototype]]: Object
    2. message: "글 상세페이지 조회에 성공했습니다."
    3. status: 200
    4. [[Prototype]]: Object

여전히 망망대해임

너무 졸려서 일단 내일 해봄

 

'Developing > 개발일지' 카테고리의 다른 글

2024-01-16, Today I Learned  (0) 2024.01.16
2024-01-15, Today I Learned  (0) 2024.01.15
2024-01-13, Today I Learned  (0) 2024.01.14
2024-01-12, Today I Learned  (0) 2024.01.12
2024-01-11, Today I Learned  (1) 2024.01.11