본문 바로가기
국비학원/수업기록

국비 지원 개발자 과정_Day61

by 루팽 2023. 2. 23.

로컬

  main(pc안에서 동작) → exe 파일 만들 수 있음

 

웹서비스

  전송방식 → GET, POST

  request(요청), response(응답) 객체 필요 → 톰캣이 주입해 줌(servlet-api.jar, jsp-api.jar)

  URL → 요청 → 사용자의 요구사항을 구분

    프로토콜://도메인주소:포트번호/폴더이름(업무명)/요청이름?(쿼리스트링)키와밸류&(&으로구분)키와밸류

    http/https 프로토콜(stateless 비상태, 상태유지 x) → 클라이언트 요청 오면 연결, 전달 후 바로 요청 끊어버림

 

인터프리터 역할(웹서비스)

  브라우저 / NodeJS → JS에 import(babel에서 사용), require(nodeJS에서 사용) 등장

 

servlet

  HttpServlet상속받아야 서블릿 → @Override 가능 doGet(요청, 응답), doPost(req, res)

  서블릿은 view역할 담당하기엔 힘들다(태그를 out.print(태그) 이렇게 하나하나 써야 하기에)

    Printwriter out = res.getWrite(); → new가 아니라 메소드로 인스턴스화 → if문 사용, 조건에 따라 객체생성 가능

    out.print(태그); → 브라우저에 써줌, 이렇게 하면 그냥 문자열(마임타입 html 지정해줘야 함)

    res.setContentType(”text/html”) → 이렇게 마임타입 지정해 주면 확장자가 java여도 html로 인식됨

 

서블릿은 싱글톤으로 관리됨(WAS가 관리) → web.xml 혹은 @WebServlet 해야 함(req, res를 관리받는 것)

  객체가 하나로만 관리됨 → 스레드 필요(순서대로 처리, 경합이 벌어짐)

if( x == null) {
	x = new Sonata();
}

 

spring에선 이런 req, res가 없어도 요청, 응답 가능 → req, res에 의존적이지 않다

 

java > servlet > jsp

 

jsp

  표준서블릿, 요청을 jsp가 받으면 mvc패턴 아님!

  (인스턴스화를 할 수 없음(WAS마다 이름이 다르기에 a.jsp → a_jsp.java → a_jsp.class)

  servlet으로 view계층 표현하기 불편하기에 jsp 탄생

  자바코드 최소한으로 작성, jsp라고 쓰고 html이라 읽는다(JS, HTML, CSS)

 

servlet

자바니까 상속가능(확장) / 사용자정의 서블릿일수도

 

response - 마임타입을 정한다. out객체를 만든다, sendRedirect 할 수 있다

request - 요청할 수 있다, 저장할 수 있다(프론트와 백 사이에-http프로토콜이라 상태가 끊어지니 상태유지, 기억하기 위해 저장)

 

<pojo step 1 - Pattern.java 패턴 테스트>

package com.pojo.step1;

public class Pattern {

	public static void main(String[] args) {
//	String url = "/chat_banana/업무이름/페이지이름|요청이름";
		String url = "/chat_banana/dept/getDeptList.kh";
		String context = "chat_banana/";
		
//	톰캣서버에 요청할 때 사용되는 주소값을 가지고 업무명과 업무에 필요한 이름으로 분리시켜
//	사용자 요청에따라 처리를 담당할 XXXController 객체를 주입하는데 사용함
		String command = url.substring(context.length()+1);
		System.out.println(command); // dept/getDeptList.kh
		
		int end = command.lastIndexOf(".");
		System.out.println(end);
		// 16
		
		command = command.substring(0, end);
		System.out.println(command);
		// dept/getDeptList
		
		String upmu[] = null;
		upmu = command.split("/");
		for(String imsi : upmu) {
			System.out.println(imsi);
			// dept
			// getDeptList
		}
	}
}

 

<pojo step 1 - web.xml FrontController1 추가>

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
	id="WebApp_ID" version="4.0">
	<!-- 
		web.xml(배치서술자 Deployment Descriptor)은 톰캣에서 제공해준다 -> 위치는 WEB-INF 아래
		서버가 처음 로딩 시 web.xml 파일을 읽어들여 환경설정에 대해 어플리케이션을 배치하게 됨
	 -->
	<!-- context-param에 등록한 정보는 톰캣서버가 기동할 때 생성되서 서버가 죽을때까지 쭉 기억한다 -->
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/WEB-INF/classes/log4.properties</param-value>
	</context-param>
	<!--
	자바로 웹서비스X / 서블릿은 가능 -> URL을 적을 수 있어서 -> xml에 등록가능(URL사용위해 서블릿을 배치)
	서블릿과 서블릿매핑은 항상 같이있어야한다
	URL을 등록(url-pattern) - URL이 있어야 요청할 수 있음
	servlet보다 servlet-mapping을 먼저 읽는다
	 -->
	<servlet>
		<servlet-name>TestServlet</servlet-name>
		<servlet-class>com.mvc.controller.TestServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>TestServlet</servlet-name>
		<url-pattern>/test/test.do</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>HelloServlet</servlet-name>
		<servlet-class>com.day1.HelloServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>HelloServlet</servlet-name>
		<url-pattern>/day1/hello.kh</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>DeptServlet</servlet-name>
		<servlet-class>com.day1.DeptManager</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>DeptServlet</servlet-name>
		<url-pattern>/jEasyUI/dept/insertAction.do</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>FrontController1</servlet-name>
		<servlet-class>com.pojo.step1.FrontMVC1</servlet-class>
	</servlet>
		<!--
			*.st1하면 어떤 요청이름이 오든 확장자가 st1으로 끝나면 FrontMVC1 서블릿이 인터셉트함
			web.xml을 수정하면 무조건 서버를 재기동해야 수정된 내용이 반영됨
		 -->
	<servlet-mapping>
		<servlet-name>FrontController1</servlet-name>
		<url-pattern>*.st1</url-pattern>
	</servlet-mapping>
	<session-config>
	  <session-timeout>10</session-timeout>
	</session-config>
</web-app>

<!--
	Deployment Descriptor 배치서술자 spring maven방식 빌드 -> pom.xml파일에 등록
	web.xml문서를 수정하면 반드시 서버를 내렸다가 다시 기동할 것(주의!)
-->

 

<pojo step 1 - Action.java>

package com.pojo.step1;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
 클래스 설계에 인터페이스가 필요하다
 인터페이스 중심의 코딩을 전개하는 것이 결합도를 낮춰준다, 의존성이 낮다, 단위테스트 가능 - 신뢰도 높이는 코드
 HttpServlet에서 강제(@Override: doGet, doPost)하는 void를 다른 타입으로 바꾸어 보자
 그래서 아래와같이 바꾸었지만 파라미터 자리의 req와 res는 개발자가 인스턴스화하는 것이 아니고
 톰캣이 주입해주는 객체이다.
 이 문제를 어떻게 해결하는지가 관전포인트!
 */
public interface Action {
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
	
}

 

<pojo step 1 - ActionForward.java>

package com.pojo.step1;

public class ActionForward {
	/*
	 	페이지 이동 방법
			1. res.sendRedirect("XXX.jsp") -표준서블릿(jsp)가 요청 받아줌 -> MVC패턴이 아니다!
			or res.sendRedirect("dept/getDeptList.kh") - 서블릿이 요청 받아줌 -> MVC패턴인가?
			
		 	jsp가 요청을 받는 것이 왜 문제인가?
	 			WAS마다 명명규칙이 다르다. 그래서 인스턴스화를 할 수 없다
	 			또한 인스턴스화를 한다 하더라도 request와 response객체를 주입받지 못하는 장애가 있다
	 			(요청, 응답, 마임타입 설정 등등 많은 것들을 못한다!)	
	*/
	private String path = null; // 응답페이지 이름 또는 서블릿의 이름
	// sendredirect로 페이지를 이동할 것인지
	// forward로 페이지를 이동할 것인지 여부를 결정함
	private boolean isRedirect = false; // true: redirect(insert|update|delete), false: forward(select)
	
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public boolean isRedirect() {
		return isRedirect;
	}
	public void setRedirect(boolean isRedirect) {
		this.isRedirect = isRedirect;
	}
}

/*
 ActionForward 클래스를 왜 만드는가?
  웹서비스에서는 main 메소드 대신에 URL로 요청을 보낸다
  누가? 클라이언트(사용자)가, 누구에게? Tomcat서버에게 요청한다
  요청을할 때 URL을 사용한다
*/

 

글목록 보기

1. 기본 10건은 항상 최신글로 조회결과를 보여준다 → 서블릿 - jsp (페이지를 출력하기 전에 DB에서 최신 10건의 글을 가져와야 함)

2. 무조건 조건검색을 통해서 조회결과를 본다 → jsp - 서블릿 - jsp

 

새 글쓰기

jsp - 서블릿(insert) - 서블릿(select) → jsp (작성한 글을 db에 저장하고 목록엔 새 글까지 출력해야 하기에 다시 db에서 가져와야 함)

 

댓글 쓰기

read.jsp(상세 보기, 기본정보 가지고 있음)

서블릿(select 1건) - jsp - 댓글쓰기버튼 - jsp - 서블릿(insert) - 서블릿(select) - jsp

 

글 수정

비밀번호인증 후에 수정할 수 있음

수정버튼 누르면 jsp - 비번입력 - 서블릿(update) - 서블릿(select) - jsp

 

글 삭제

비밀번호인증 후에 삭제할 수 있음

삭제버튼 누르면 jsp - 비번입력 - 서블릿(delete) - 서블릿(select) - jsp

 

<pojo step 1 - FrontMVC1.java>

package com.pojo.step1;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

public class FrontMVC1 extends HttpServlet {
	Logger logger = Logger.getLogger(FrontMVC1.class);

	protected void doService(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		logger.info("doService 호출");
		String uri = req.getRequestURI();
		logger.info(uri); // /dept/getDeptList.st1이 찍힘
		String context = req.getContextPath(); // "/" -> server.xml에 들어있음
		logger.info(context);

		// 테스트: http://localhost:9000/업무폴더명/요청기능이름.st1
		// 예시1: http://localhost:9000/dept/getDeptList.st1
		// 예시2: http://localhost:9000/member/getMemberList.st1
		// 예시3: http://localhost:9000/board/getBoardList.st1
		// 예시4: http://localhost:9000/board/BoardInsert.st1
		// 예시5: http://localhost:9000/board/BoardUpdate.st1
		// 예시6: http://localhost:9000/board/BoardDelete.st1
		String command = uri.substring(context.length() + 1);
		System.out.println(command); // dept/getDeptList.st1

		int end = command.lastIndexOf("."); // end는 .st1 잘라내기위해 사용
		System.out.println(end); // 16(dept의 경우)

		command = command.substring(0, end);
		System.out.println(command); // dept/getDeptList

		String upmu[] = null; // upmu[0]=업무명(폴더명), upmu[1]=요청기능이름(메소드명)
		upmu = command.split("/");
		for (String imsi : upmu) {
			System.out.println(imsi); // upmu[0]=dept, upmu[1]=getDeptList
		}

		// 게으른 인스턴스화 - 필요할 때 주입
		// 아직 업무명이 결정되지 않았다 - 업무명(upmu[0])이 Controller클래스의 접두어이다
		DeptController deptController = null;
		EmpController empController = null;
		ActionForward af = null;

		/*
		 * DeptController에서 req와 res를 받을 수 있는건 execute(req, res)메소드 뿐이다 그렇기에 각 기능별로
		 * 사용하려면 메소드로 나누면 안될 것 같다 그럼 if문으로 분기하고 DeptLogic.java에서 메소드를 분리해보자
		 */

		// request 객체는 저장소이다 - setAttribute, getAttribute
		// req.setAttribute로 upmu[]를 DeptController로 전달(메소드에서 사용하기위해서)
		req.setAttribute("upmu", upmu);

		if ("dept".equals(upmu[0])) {
			// 인스턴스화 -> execute() 호출하기위해 -> 안하면 NullPointerException이니까(서버쪽은 500번)
			deptController = new DeptController();
			// deptController는 서블릿이 아니여서 req, res를 WAS로부터 주입받을 수 없다(상속안받았기에)
			// 그렇기에 af execute() 호출
			af = deptController.execute(req, res);
		} else if ("emp".equals(upmu[0])) {
			// 인스턴스화
			empController = new EmpController();
			af = empController.execute(req, res);
		}

		// 페이지 이동 처리 공통코드로 만들기
		// res.sendRedirect("/dept/getDeptList.jsp"); -> jsp(요청) - 서블릿 - jsp(응답)
		// res.sendRedirect("/dept/getDeptList.st1"); -> jsp - 서블릿 - 서블릿 - jsp
		if (af != null) {
			if (af.isRedirect()) {
				res.sendRedirect(af.getPath());
			} else {
				RequestDispatcher view = req.getRequestDispatcher(af.getPath());
				view.forward(req, res);
			}
		} // end of 페이지 이동처리에 대한 공통 코드 부분
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		doService(req, res);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		doService(req, res);
	}
}

 

DeptController에서 req와 res를 받을 수 있는 건 execute(req, res)메소드 뿐이다

그렇기에 각 기능별로 사용하려면 메소드로 나누면 안 될 것 같다

그럼 if문으로 분기하고 DeptLogic.java에서 메소드를 분리해 보자

 

DeptLogic.java - 트랜잭션 처리(묶음배송-모든 요소가 있어야 전달, 하나의 프로세스)

DeptDao.java - DB연동만 전담/orm솔루션사용

 

<pojo step 1 - DeptController.java>

package com.pojo.step1;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

//SELECT deptno, dname, loc FROM dept
public class DeptController implements Action {
	Logger logger = Logger.getLogger(DeptController.class);

	// Action 인터페이스 상속 후 오버라이드한 메소드, 반환값이 ActionForward
	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		ActionForward af = new ActionForward();
		String upmu[] = (String[]) req.getAttribute("upmu"); // FrontMVC1에서 가져온 값
		DeptLogic deptLogic = new DeptLogic();
		String path = null;
		boolean isRedirect = false;

		// 부서목록 조회인 경우 - http://localhost:9000/dept/getDeptList.st1
		if ("getDeptList".equals(upmu[1])) {
			List<Map<String, Object>> deptList = deptLogic.getDeptList();
			req.setAttribute("deptList", deptList);
			path = "getDeptList.jsp";
			isRedirect = false; // false이면 forward이다 - 요청이 유지된다, 주소창은 그대로 페이지만 바뀜
		}
		// json 부서목록 조회인 경우
		else if ("jsonDeptList".equals(upmu[1])) {
			String jsonDoc = deptLogic.jsonDeptList();
			req.setAttribute("jsonDoc", jsonDoc);
			path = "jsonDeptList.jsp";
			isRedirect = false; // false이면 forward이다 - 요청이 유지된다, 주소창은 그대로 페이지만 바뀜
		}
		// 부서 등록인 경우
		else if ("deptInsert".equals(upmu[1])) {
			// insert into dept (deptno, dname, loc) values(?, ?, ?)
			int result = deptLogic.deptInsert();
		}
		// 부서 정보 수정인 경우
		else if ("deptUpdate".equals(upmu[1])) {
			int result = deptLogic.deptUpdate();
		}
		// 부서 삭제인 경우
		else if ("deptDelete".equals(upmu[1])) {
			int result = deptLogic.deptDelete();
		}

		af.setPath(path);
		af.setRedirect(isRedirect);
		return af;
	}

	public ActionForward getDeptList() {
		// 이렇게 메소드를 만들면 req, res가 없음
		// res가 없으면 res.sendRedirect();를 못함! -> res에 의존적
		return null;
	}
}

 

<pojo step 1 - DeptLogic.java>

package com.pojo.step1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.google.gson.Gson;

public class DeptLogic {
	Logger logger = Logger.getLogger(DeptLogic.class);

	public List<Map<String, Object>> getDeptList() {
		logger.info("getDeptList 호출");
		List<Map<String, Object>> deptList = new ArrayList<>();
		Map<String, Object> rMap = new HashMap<>();
		rMap.put("deptno", 10);
		rMap.put("dname", "개발부");
		rMap.put("loc", "부산");
		deptList.add(rMap);
		rMap = new HashMap<>();
		rMap.put("deptno", 20);
		rMap.put("dname", "운영부");
		rMap.put("loc", "서울");
		deptList.add(rMap);
		rMap = new HashMap<>();
		rMap.put("deptno", 30);
		rMap.put("dname", "총무부");
		rMap.put("loc", "대전");
		deptList.add(rMap);
		return deptList;
	}

	public String jsonDeptList() {
		logger.info("jsonDeptList 호출");
		List<Map<String, Object>> deptList = new ArrayList<>();
		Map<String, Object> rMap = new HashMap<>();
		rMap.put("deptno", 10);
		rMap.put("dname", "개발부");
		rMap.put("loc", "부산");
		deptList.add(rMap);
		rMap = new HashMap<>();
		rMap.put("deptno", 20);
		rMap.put("dname", "운영부");
		rMap.put("loc", "서울");
		deptList.add(rMap);
		rMap = new HashMap<>();
		rMap.put("deptno", 30);
		rMap.put("dname", "총무부");
		rMap.put("loc", "대전");
		deptList.add(rMap);
		Gson g = new Gson();
		String temp = g.toJson(deptList);
		return temp; // JSON 포맷으로 전달 -> 리액트에서 조회시에 사용함
	}

	public int deptInsert() {
		logger.info("deptInsert 호출");
		return 0;
	}

	public int deptUpdate() {
		logger.info("deptUpdate 호출");
		return 0;
	}

	public int deptDelete() {
		logger.info("deptDelete 호출");
		return 0;
	}

}

 

<pojo step 1 - getDeptList.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="java.util.List, java.util.Map"%>
<%
List<Map<String, Object>> deptList = (List<Map<String, Object>>) request.getAttribute("deptList");
out.print(deptList);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>부서목록</title>
</head>
<body>

</body>
</html>

 

<pojo step 1 - jsonDeptList.jsp>

<%@ page language="java" contentType="application/json; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true"%>
<%
String jsonDoc = (String) request.getAttribute("jsonDoc");
out.print(jsonDoc);
%>

 

<리액트 톰캣 연결 - dbLogic.js>

import axios from "axios";

export const jsonDeptList = (params) => {
  return new Promise((resolve, reject) => {
    try {
      const response = axios({
        method: "get",
        url: process.env.REACT_APP_CHAT_BANANA_IP + "dept/jsonDeptList.st1",
        params: params,
      });
      resolve(response);
    } catch (error) {
      reject(error);
    }
  });
};

/* rafce로 자동완성 단축키 - arrow function export default */

 

리액트와 서블릿 연동하기 - chat_banana[D:\workspace_java\chat_banana]
  : yarn 패키지 매니저 사용함
  설치 시 -g를 주면 전역에서 사용가능하게 설치

  (-D는 개발자 의존성 주입: spring maven, gradle도 동일)
      npm install -g yarn

  패키지매니저 버전확인
    yarn -version

리액트 프로젝트 생성하기
  1. yarn create react-app template2023
    단, 현재 바라보는 폴더 아래에 template2023 폴더가 생성된다
    VSCode로 프로젝트 열 때도 위 경로에서 열어야 에러가 없음
    지금 이 프로젝트는 D:\workspace_java\chat_banana\src\main에서 생성함

  2. yarn init --force
    그냥 계속 엔터 하면 디폴트값으로 package.json에 등록됨

  3. react-router-dom 설치 -> 웹페이지 제작에 필수(화면전환 역할 - 링크도 포함)
    yarn add react-router-dom
    index.js에 아래와 같이 BrowserRouter를 추가해야 한다 - 단 App.jsx를 감싸준다
      <React.StrictMode>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </React.StrictMode>

  4. CSS 추가분
    React-BootStrap
      yarn add react-bootstrap

    만약 React-BootStrap에 미지원 부분에 대해서는 BootStrap을 설치하여 사용자정의 CSS로 처리
      yarn add bootstrap -> css라이브러리 설치 시

    CSS를 자바스크립트 문법으로 처리해 주는 styled-components
      yarn add styled-components

  5. 폰트어썸 무료 이모티콘, 이모지
    yarn add @fortawesome/fontawesome-free
  
  6. axios 설치 - 비동기 처리 -> 톰캣서버의 서블릿 요청함
    yarn add axios

    fetch API에서 지원 안 되는 json포맷 지원받음
    Moesif CORS - true/false
    주의: CORS이슈


    import axios from "axios";

    export const jsonDeptList = (params) => {
      return new Promise((resolve, reject) => {
        try {
          const response = axios({
            method: "get",
            url: process.env.REACT_APP_CHAT_BANANA_IP + "dept/jsonDeptList.st1",
            params: params,
          });
          resolve(response);
        } catch (error) {
          reject(error);
        }
      });
    };
    /* rafce로 자동완성 단축키 - arrow function export default */

  7. firebase 설치 - 9.17.1
    yarn add firebase

    로그인 인증
    회원가입 지원
    RealtimeDatabaseServer - 채팅기능 활용(30일)
    storage - 이미지, 동영상(30일)

  8. .env 사용
    구글 키값, 카카오 키값 관리용도
    .gitignore에 등록할 것

  9. 실행하기
    yarn start
    http://localhost:3000/index.html 실행됨 -> div id="root"

    사용자정의태그 Paint와 Nice도 사용가능
    ReactDOM.createRoot(rootElement).render(element(<Paint/> <Nice/>))

    index.html -> index.js -> BrowserRouter로 App.jsx를 감싸줌 -> App.jsx에서 Route 통해 페이지 링크

 

<리액트 BrowserRouter 테스트 - index.js>

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";

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

 

<리액트 BrowserRouter 테스트 - App.jsx>

import { Route, Routes } from 'react-router-dom';
import './App.css';
import DeptPage from './components/page/DeptPage';
import EmpPage from './components/page/EmpPage';
import HomePage from './components/page/HomePage';

function App() {
  return (
    <>
      <Routes>
        <Route path="/" exact={true} element={<HomePage />} />
        <Route path="/dept/:id" exact={true} element={<DeptPage />} />
        <Route path="/emp" exact={true} element={<EmpPage />} />
      </Routes>
    </>
  );
}

export default App;

 

<리액트 BrowserRouter 테스트 - Header.jsx>

import React from 'react'

const Header = () => {
  return (
    <div>
      Header
    </div>
  )
}

export default Header

 

<리액트 BrowserRouter 테스트 - Bottom.jsx>

import React from 'react'

const Bottom = () => {
  return (
    <div>
      Bottom
    </div>
  )
}

export default Bottom

 

<리액트 BrowserRouter 테스트 - HomePage.jsx>

import React from 'react'

const HomePage = () => {
  return (
    <div>
      HomePage 페이지
    </div>
  )
}

export default HomePage

 

<리액트 BrowserRouter 테스트 - DeptPage.jsx>

import React from 'react'
import Bottom from '../include/Bottom'
import Header from '../include/Header'

const DeptPage = () => {
  return (
    <>
      <Header />
      <div>부서관리 페이지</div>
      <Bottom />
    </>
  )
}

export default DeptPage

 

<리액트 BrowserRouter 테스트 - EmpPage.jsp>

import React from 'react'
import Bottom from '../include/Bottom'
import Header from '../include/Header'

const EmpPage = () => {
  return (
    <React.Fragment>
      <Header />
        사원관리시스템
      <Bottom />
    </React.Fragment>
  )
}

export default EmpPage

댓글