1부에 이어, 2부에서는 Map Component를 그리고, 지도가 표출되도록 하겠습니다.

 

이에 앞서 1부에서 CRA를 통해 설치 된 리액트 버전이 v18인데 v17로 다운그레이드 하겠습니다.

 

* 참고 자료

https://homubee.tistory.com/36

 

[React] 리액트 버전 낮추기(변경/다운그레이드) + 오류 해결

오늘은 리액트 버전 낮추는 방법에 관해 알아보겠습니다. 진행하며 발생할 수 있는 오류까지 자세히 살펴볼 예정입니다. 종속성 문제 때문에 최신 버전이 아닌 리액트를 사용해야 하는 경우가

homubee.tistory.com

1부에서 설치되지 않았던 @mui/styles를 설치하겠습니다.

D:\workspace_vscode\react_google_map> npm install @mui/styles

 

/src/component/Map 하위에 styles.js 파일을 추가하고 여기에 Map.js의 css를 구성하겠습니다.

// styles.js

import { makeStyles } from "@mui/styles";

export default makeStyles(() => ({
  paper: {
    padding: "10px",
    display: "flex",
    flexDirection: "columns",
    justifyContent: "center",
    width: "100px",
  },
  mapContainer: {
    height: "85vh",
    width: "100%",
  },
}));
// Map.js

import React from "react";
import GoogleMapReact from "google-map-react";

import useStyle from "./styles";

const Map = () => {
  const classes = useStyle();
  const cordinates = { lat: 0, lng: 0 };
  return (
    <div className={classes.mapContainer}>
      <GoogleMapReact
        bootstrapURLKeys={{ key: "" }}
        defaultCenter={cordinates}
        center={cordinates}
        defaultZoom={14}
        margin={[50, 50, 50, 50]}
        options={""}
        onChange={""}
        onChildClick={""}
      ></GoogleMapReact>
    </div>
  );
};

export default Map;

google-map-react 라이브러리를 import 하고, 위와 같이 작성해줍니다.

bootstrapURLKeys 부분의 key 값에 대해서는 google project를 만들어 key값을 받아와야 합니다.

(발급방법은 자세히 설명 된 타글을 링크해놓겠습니다.)

* 참고자료

https://velog.io/@sukqbe/API-%EA%B5%AC%EA%B8%80-%EC%A7%80%EB%8F%84Google-Map-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0-API-Key-%EB%B0%9C%EA%B8%89%EB%B0%9B%EA%B8%B0-qumur49u

 

[API] 구글 지도(Google Map) 추가하기 (+ API Key 발급받기)

구글 지도(Google Map) API Key 발급 및 사용법

velog.io

 

위와같이 작성 후 프로젝트를 실행하면 아래와 같이 화면이 뜹니다.

해당 알림창은 우리가 아직 key값을 부여하지 않았기에 뜨는 내용이며, 지도를 최소로 축소하면 다음과 같이 지도가 정상적으로 뜨고있음을 알 수 있습니다.

 

 

 

* 참고 자료

https://www.npmjs.com/package/google-map-react

 

google-map-react

Isomorphic component that allows rendering react components on a google map. Latest version: 2.2.0, last published: 2 months ago. Start using google-map-react in your project by running `npm i google-map-react`. There are 316 other projects in the npm regi

www.npmjs.com

https://velog.io/@jhs000123/%EB%A6%AC%EC%95%A1%ED%8A%B8-googlemap%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8

 

리액트 - googlemap을 이용한 프로젝트

googlemap 을 이용해서 주변 지역의 맛집을 보여주는 맛지도 프로젝트를 제작한다. 식당의 종류, 평점별로 검색이 가능하며 지도에는 해당 위치에 나타나는 식당의 이미지를 보여줄 것이다.rapidAPI

velog.io

 

1. create-react-app을 통해 기본적은 react 프로젝트를 생성합니다.

D:\workspace_vscode> npx create-react-app react_google_map

 

2. 생성 된 프로젝트가 정상적으로 실행되는지 확인합니다.

D:\workspace_vscode> npm run start

 

3. 불필요한 코드를 정리합니다.

// index.js

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
// App.js

import React from "react";

function App() {
  return <div>app.js</div>;
}

export default App;

 

4. /src/component/Map 패키지 구조를 생성하고 Map.js, index.js를 생성합니다.

// /src/component/Map/index.jsp

export { default } from "./Map";
// /src/component/Map/Map.js

import React from "react";

const Map = () => {
  return <div>Map</div>;
};

export default Map;

 

5. App.js에서 Map.js를 import합니다.

// App.js

import React from "react";
import Map from "./component/Map";

function App() {
  return (
    <div>
      <Map />
    </div>
  );
}

export default App;

 

6. 이제 프로젝트를 진행함에 있어 필요한 항목들을 설치합니다.

D:\workspace_vscode\react_google_map> npm install @mui/material @mui/icons-material axios google-map-react

@mui/material, @mui/icons-material : 자주 사용되는 기능, 디자인을 component/API 형태로 제공하여, React 개발시에 유용한 라이브러리 입니다.

axios : 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리 입니다.

google-map-react : 구글 지도 검색창 구현을 위한 라이브러리 입니다.

 

7. package.json에서 확인해야 할 사항

현재 npx를 통해 설치 된 react 버전이 v18버전인데, 추후 해당 버전과 google-map-react와의 이슈로 인해 다운그레이드를 할 예정입니다.(v17) 이에따라 React v17용으로 index.js의 변경이 있을 예정입니다.

2. MySQL

    InnoDB 스토리지 엔진

    Repeatable read 이상 방식을 사용 -> 부정합 발생하지 않습니다.

 

리핏테이블 리드 방식에서는 트랜젝션이 종료되지 않은 순간까지는 동일한 조회 결과가 나옵니다.

보통 스프링에서 CRUD에서 CUD에서만 트랜잭셔널 어노테이션을 붙이게 되는데, R에서도 트랜잭셔널 어노테이션을 붙이는게 좋습니다.

 

 

강의 주소 : https://youtu.be/n1lvzeffDMk

- 일어날 수 있는 문제의 경우

위와같이 정산 서비스에 대해서 조회시 만원의 결과를 보여주다가 어느순간 커밋이후 2만원으로 결과가 보여진다면, 데이터의 정합성이 깨지는 것입니다.

이러한 현상을 PHANTOM READ(팬텀 리드)라 합니다.

 

이러한 팬텀 리드 현상을 해결하기 위해서는REPEATABLE READ 방식을 써야 합니다.

 

 

 

 

강의 주소 : https://youtu.be/4iDNmluK6DE

- 트랜잭션 : 일이 처리되기 위한 가장 작은 단위

 

- DB 격리 수준

  1. 오라클

      READ COMMIT

오라클의 경우는 변경하려고하는 데이터가 커밋이 되기 전까지는 undo영역의 데이터를 읽어옵니다.

좌측의 A트랜잭션이 업데이트 후 커밋 직전에 B트랜잭션에서 empno=11을 조회하게 되면, 장보고가 아닌 임꺽정이 조회됩니다.

 

 

강의 주소 : https://youtu.be/FbeU3ZHgOhs

- ResponseDto.java의 status의 형태를 HttpStatus -> int로 변경합니다.

package com.cos.blog.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseDto<T> {
	int status;
	T data;
}

 

- UserApiController.java

package com.cos.blog.controller.api;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.cos.blog.dto.ResponseDto;
import com.cos.blog.model.RoleType;
import com.cos.blog.model.User;
import com.cos.blog.service.UserService;

@RestController
public class UserApiController {

	@Autowired
	private UserService userService;
	
	@PostMapping("/api/user")
	public ResponseDto<Integer> save(@RequestBody User user) {
		
		user.setRole(RoleType.USER);
		int result = userService.회원가입(user);
		
		return new ResponseDto<Integer>(HttpStatus.OK.value(), result);
	}
}

 

- GlobalExceptionHandler.java

package com.cos.blog.handler;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

import com.cos.blog.dto.ResponseDto;

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {

	@ExceptionHandler(value=Exception.class)
	public ResponseDto<String> handleArgumentException(IllegalArgumentException e) {
		return new ResponseDto<String>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
	}
}

 

 

강의 주소 : https://youtu.be/f5zHFb1BHmY

@Service : 스프링이 컴포넌트 스캔을 통해서 Bean에 등록을 해주는 어노테이션입니다.(IoC)

 

- UserService.java 파일을 생성합니다.

package com.cos.blog.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cos.blog.model.User;
import com.cos.blog.repository.UserRepository;

// 스프링이 컴포넌트 스캔을 통해서 Bean에 등록을 해줌. IoC
@Service
public class UserService {

	@Autowired
	private UserRepository userRepository;
	
	public int 회원가입(User user) {
		try {
			userRepository.save(user);
			return 1;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("UserService : 회원가입() : " + e.getMessage());
		}
		
		return -1;
	}
}

 

* Service가 필요한 이유

1. 트랜잭션 관리 -> 다음시간에 설명!

2. 서비스의 의미 때문

송금서비스로 예를 들어보겠습니다.

위의 경우 2개의 서비스가 존재합니다.

이때 홍길동의 송금은 정상처리되었으나, 임꺽정의 입금이 오류가 발생했다면 전체 서비스는 롤백이 됩니다.

하나하나의 일을 트랜잭션이라 하며, 이 트랜잭션들을 묶어서 서비스라 합니다.

 

 

 

 

강의 주소 : https://youtu.be/I-2Bug08D3Y

user.js를 생성하여 아래와 같이 작성합니다.

let index = {
	init: function() {
		$('#btn-save').on('click', () => { // function(){}, ()=>{} this를 바인딩하기 위해서!!
			this.save();
		});
	}
	
	, save: function() {
//		alert('user의 save함수 호출됨');
		let data = {
			user: $('#username').val(),
			password: $('#password').val(),
			email: $('#email').val()
		};
		
//		console.log(data);
		
		// ajax호출시 default가 비동기 호출
		// ajax 통신을 이용해서 3개의 데이터를 json으로 변경하여 insert 요청!!
		// ajax가 통신을 성공하고 서버가 json을 리턴해주면 자동으로 자바 오브젝트로 변환해준다.
		$.ajax({
			type : 'POST',
			url : '/blog/api/user',
			data : JSON.stringify(data), // http body데이터
			contentType : 'application/json; charset=utf-8', // body데이터가 어떤 타입인지(MIME)
			dataType : 'json' //요청을 서버로해서 응답이 왔을 때 기본적으로 모든 것이 문자열 (생긴게 json이라면) => javascript 오브젝트로 변환
		}).done(function(resp) {
			alert('회원가입이 완료되었습니다.');
//			console.log(resp);
			location.href = '/blog';
		}).fail(function(error) {
			alert(JSON.stringify(error));
		}); 
	}
}

index.init();

 

- ajax를 통한 회원가입 요청하기

위에서 jquery 라이브러리의 ajax를 통해 서버쪽으로 회원가입 서비스를 호출합니다.

이때 송신하는 데이터에 대해서는 json형태로 하여 보내주며, contentType도 작성 된 내용과 같이 작성합니다.

또한, response에 대해 dataType을 json으로 받겠다고 명시합니다.

(강의 내용 중 jquery버전 상승으로 인해 dataType을 명시하지 않아도 자동적으로 object형태로 변환해줍니다.)

 

- UserApiController.java 생성

package com.cos.blog.controller.api;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.cos.blog.dto.ResponseDto;
import com.cos.blog.model.User;

@RestController
public class UserApiController {

	@PostMapping("/api/user")
	public ResponseDto<Integer> save(@RequestBody User user) {
		
		return new ResponseDto<Integer>(HttpStatus.OK, 1);
	}
}

 

데이터를 반환하기때문에 RestContorller 어노테이션을 선언했으며, save메소드에 대해 반환타입은 ResponseDto<Integer>로 했습니다.

 

- ResponseDto.java

package com.cos.blog.dto;

import org.springframework.http.HttpStatus;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseDto<T> {
	HttpStatus status;
	T data;
}

ResponseDto는 Generic 파라미터를 받아 처리하게 하였습니다.

Generic에 대한 자세한 설명은 아래 링크를 참고하세요.

https://jehuipark.github.io/java/java-generic

 

[JAVA] 제네릭(Generic)이란

List<Interger> list1 = new ArrayList<>();List list2 = new ArrayList<>();Map<String, String> map = new ArrayList<>();

jehuipark.github.io

 

 

 

 

강의 주소 : https://youtu.be/809058DGUPo

2. 비동기 통신을 하기 위해서이다.

 

 

강의 주소 : https://youtu.be/2PMMQHok3U4

1. 요청에 대한 응답을 html이 아닌 Data(json)를 받기 위하여

 

 

강의 주소 : https://youtu.be/2PMMQHok3U4

+ Recent posts