D+60::사원관리페이지만들기_최종(Emp)

Am.Vinch·2022년 9월 21일
0

20220921_tue

실습 예제(기출)


사원관리 페이지 만들기_스프링부트

프로젝트 생성 기초 세팅

  • porm.xml
    : dependency 태그 3개 추가
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.3</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>Kh.study</groupId>
	<artifactId>Shop</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>Shop</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.2.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.oracle.database.jdbc</groupId>
			<artifactId>ojdbc8</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- log4jdbc : 쿼리실행은 콘솔에 출력하기 위해 추가 -->
		<dependency>
			<groupId>org.bgee.log4jdbc-log4j2</groupId>
			<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
			<version>1.16</version>
		</dependency>

		<!-- 타임리프의 fragment 기능 사용을 위한 추가 -->
		<dependency>
			<groupId>nz.net.ultraq.thymeleaf</groupId>
			<artifactId>thymeleaf-layout-dialect</artifactId>
			<version>3.1.0</version>
		</dependency>
		<!--  validation처리 추가 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>
s
  • application.properties
    : 연동할 DB 계정 아이디와 비밀번호 값 정확히 설정하기
# PORT 포트
server.port=8081

# thymeleaf 캐쉬 설정
spring.thymeleaf.cache=false

#spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
#spring.datasource.url=jdbc:oracle:thin:@127.0.0.1:1521/xe
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xe
spring.datasource.username=MYDB
spring.datasource.password=ORACLE

#xml location
#mybatis.mapper-locations=classpath:mappers/**/*.xml
mybatis.mapper-locations=classpath:mappers/*.xml
  • log4jdbc.log4j2.prperties
    : 복사 붙여넣기
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0
  • logback.xml
    :복사 붙여넣기
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{yyyyMMdd HH:mm:ss.SSS} [%thread] %-3level %logger{5} - %msg %n</pattern>
    </encoder>
  </appender>
  
  <logger name="jdbc" level="OFF"/>
  
  <logger name="jdbc.sqlonly" level="OFF"/>
  <logger name="jdbc.sqltiming" level="DEBUG"/>
  <logger name="jdbc.audit" level="OFF"/>
  <logger name="jdbc.resultset" level="OFF"/>
  <logger name="jdbc.resultsettable" level="DEBUG"/>
  <logger name="jdbc.connection" level="OFF"/>
  
  <root level="INFO">
    <appender-ref ref="STDOUT" />
  </root>
  
</configuration>

1. 홈화면 만들기


회사에서 직원을 관리하기 위한 웹 프로그램을 개발하려고 한다.
우리는 프로그램을 통해 부서와 직원을 등록하고,등록된 직원의 목록을 보여주는
화면을 개발해야 한다.
이를 위해 데이터베이스를 생각해본 결과, 사원정보를 관리하는 테이블과
부서 정보를 관리하는 테이블이 필요할 것으로 보인다.
아래 정보는 테이블 정보와 개발에 필요한 파일명을 나열한 것이다.
문제를 풀어나가며 프로그램을 완성해보자.

  • DB: 테이블 정보
    부서정보(TEST_DEPARTMENT) - 부서번호(PK),부서명, 지역
    직원정보(TEST_EMP) - 사원번호(PK), 사원명, 직급, 나이, 성별,연락처, 부서번호(FK)
    두 테이블에서 연락처를 제외한 모든 데이터는 필수 입력값으로 설정한다.
    부서번호는 DEPT001,DEPT002,DEPT003… 의 패턴으로 등록된다.
    사원번호는 EMP001,EMP002,EMP003…의 패턴으로 등록된다.
    위의 이미지 예시는 프로그램 시작 시 나타나는 화면이다. 또한, 상단 메뉴에서 ‘홈‘
    메뉴를 클릭해도 위의 페이지가 나타나야 한다.

2. 부서관리 화면 만들기


부서관리화면에서는 부서를 등록할 수 있고, 등록된 부서목록을 표의 형태로
나타내어야 한다. 아래의 요구사항을 만족할 수 있도록 해당 페이지를 구현하세요.
-메뉴에서 ‘부서관리’ 클릭 시 해당 페이지가 나와야 한다.
-부서번호(PK)는 DEPT001,DEPT002…의 패턴으로 등록되어야 한다.
-지역은 서울,부산,대전,대구,인천 등의 데이터만 들어갈 수 있도록 셀렉트
박스로 구현한다.
-‘등록’버튼 클릭 시 다시 ‘부서관리'페이지로 이동해야 한다.
-부서명은 임의로 등록하면 된다.
-부서목록은 위의 예시와 유사하게 출력하도록 한다.(표의 디자인은 제외)
-만약 부서번호(PK)를 제시한 패턴으로 만들기 어렵다면 1,2,3…의 패턴으로 1씩 자동증가되도록 구현한다.

3. 사원등록 화면 만들기


사원등록 화면은 위의 예시처럼 만든다. 요구사항은 다음과 같다.

  • 연락처를 제외한 모든 데이터는 필수 입력값이다.
    -사원번호(PK)는 EMP001,EMP002…의 패턴으로 등록되어야 한다.
    -직급은 부장,과장,대리,사원 데이터만 입력받을 수 있도록 셀렉트박스로 구현한다.
    -부서 정보는 데이터베이스에 입력된 부서 정보 중 선택할 수 있도록 셀렉트박스로
    구현한다.
    -나이는 최소값1,최대값 70으로 설정하고, DEFAULT값으로 20을 설정한다.
    -연락처는 세 개의 INPUT태그로 구성되어있고,세 개의 값을
    연결하여 연락처 정보가 된다.
    -만약 사원번호(PK)를 제시한 패턴으로 만들기 어렵다면 1,2,3…의 패턴으로 1씩 자동증가되도록 구현한다.
    -등록 버튼을 클릭하여 사원이 등록되면 사원목록페이지로 이동해야 한다.

4. 사원목록 화면 만들기


사원등록 화면은 위의 예시처럼 만든다. 요구사항은 다음과 같다.

  • 모든 회원의 정보가 목록으로 나와야한다.
  • 사원 목록은 사전 편찬순으로 정렬되어야 한다.
  • 모든 정보는 가로 가운데 정렬로 한다

DB

  • DB(오라클)
    : '사원관리.sql' 파일 생성
    : 주의) 연결계정명: MYDB -> application 파일 작성시 유의할 것!
DROP TABLE TEST_DEPARTMENT;
create TABLE TEST_DEPARTMENT(
    DEPT_NO VARCHAR2(100) CONSTRAINT DEPT_PK PRIMARY KEY --DEPT001,DEPT002,DEPT003…
    , DEPT_NAME VARCHAR2(50) NOT NULL
    , LOC VARCHAR2(50) NOT NULL
);
select * from TEST_EMP;
select * from TEST_DEPARTMENT;

DROP TABLE TEST_EMP;
CREATE TABLE TEST_EMP(
    EMP_NO VARCHAR2(100) CONSTRAINT EMP_PK PRIMARY KEY --EMP001,EMP002,EMP003
    , EMP_NAME VARCHAR2(50) NOT NULL
    , JOB VARCHAR2(50) NOT NULL
    , AGE NUMBER NOT NULL
    , GENDER VARCHAR2(30) NOT NULL
    , TELL VARCHAR2(100) --010-111-222
    , DEPT_NO VARCHAR2(100) CONSTRAINT EMP_FK REFERENCES TEST_DEPARTMENT(DEPT_NO) not null
);

-- *중요*
-- 다음에 들어갈 deptNo 값 조회
-- dept001,dept002...
-- DEPT001 에서 5번째 글자부터 가져오는데 SUBSYR문자열이기때문에 MAX사용하려면 숫자로 형변환
SELECT 
NVL(MAX(TO_NUMBER(SUBSTR(DEPT_NO,5))),0)+1 
FROM TEST_DEPARTMENT;

springboot_패키지 및 파일 생성

dept_패키지

  • DeptController
package kh.study.emp.dept.controller;

@Controller
@RequestMapping("/dept")
public class DeptController {
	@Resource(name = "deptService")
	private DeptService deptService;
	
	//부서관리페이지이동(부서등록 +  부서목록조회)
	@GetMapping("/manage")
//	<!-- 커맨드객체 주의할점!!! 컨트롤러에서 매개변수로 DeptVO 를 만약 dept라고 변수명을 적어도
//    커맨드객체사용을 하려면 무조건 deptVO처럼 객체명을 모두 소문자로 바꾼 채로만 사용가능하다!! -->
	public String deptManage(Model model,DeptVO deptVO) {
		//부서목록조회
		model.addAttribute("deptList",deptService.selectDept());
		return "content/manage";
	}
	
	//부서등록
	@PostMapping("/regDept")
	public String regDept(DeptVO deptVO) {
		deptService.insertDept(deptVO);
		return"redirect:/dept/manage";
	}
	
	//부서목록조회
	@GetMapping("/reg")
	public String deptList(Model model) {
		//부서목록조회
		model.addAttribute("deptList", deptService.selectDept());
		return "content/manage";

	}
}
  • DeptService
package kh.study.emp.dept.service;

public interface DeptService {
	List<DeptVO> selectDept();
	void insertDept(DeptVO deptVO);
}
  • DeptServiceImpl
package kh.study.emp.dept.service;

@Service("deptService")
public class DeptServiceImpl implements DeptService {
	@Autowired
	private SqlSessionTemplate sqlSession;
	
	//목록조회
	@Override
	public List<DeptVO> selectDept() {
		return sqlSession.selectList("deptMapper.selectDept");
	}
	//부서등록
	@Override
	public void insertDept(DeptVO deptVO) {
		sqlSession.insert("deptMapper.insertDept",deptVO);
	}
}
  • DeptVO
package kh.study.emp.dept.vo;

@Getter
@Setter
@ToString
public class DeptVO {
	private String deptNo;
	private String deptName;
	private String loc;
}

Emp_패키지

  • EmpController
package kh.study.emp.emp.controller;

@Controller
@RequestMapping("/emp")
public class EmpController {
	@Resource(name = "empService")
	private EmpService empService;
	
	@Resource(name = "deptService")
	private DeptService deptService;
	
	//첫 홈 화면
	@GetMapping("/home")
	public String home() {
		return "content/home";
	}
	
	//사원등록 메뉴버튼 클릭시 이동
	@GetMapping("/regEmp")
	public String regEmpForm(EmpVO empVO,DeptVO deptVO,Model model) {
		//부서목록조회
		model.addAttribute("deptList", deptService.selectDept());
		return "content/reg";
	}
	
	//사원등록 하러가기(form태그)
	//*** 연락처 tell input태그 3개를 어떻게 가져올 것인가?
	//우리가 넣어야할 방법은 010-3333-4444 이다
	//---- replace 함수 사용하기-------------------//
	@PostMapping("/regEmp")
	public String regEmp(EmpVO empVO) {
//		empVO.getTell(); // "010,1111,2222" 
//		String tell = empVO.getTell().replace(",", "-");
//		System.out.println(tell);//010,1111,2222 --> 010-1111-2222
//		empVO.setTell(tell);
		
		//요약하여 한줄로 만들기
		empVO.setTell(empVO.getTell().replace(",", "-"));
		
		empService.insertEmp(empVO);
		return "redirect:/emp/list";
	}
	
	//사원목록
	@GetMapping("/list")
	public String list(Model model) {
		model.addAttribute("empList", empService.selectEmp());
		return "content/list";
	}
	
}
  • EmpService
package kh.study.emp.emp.controller;
@Controller
@RequestMapping("/emp")
public class EmpController {
	@Resource(name = "empService")
	private EmpService empService;
	
	@Resource(name = "deptService")
	private DeptService deptService;
	
	//첫 홈 화면
	@GetMapping("/home")
	public String home() {
		return "content/home";
	}
	
	//사원등록 메뉴버튼 클릭시 이동
	@GetMapping("/regEmp")
	public String regEmpForm(EmpVO empVO,DeptVO deptVO,Model model) {
		//부서목록조회
		model.addAttribute("deptList", deptService.selectDept());
		return "content/reg";
	}
	
	//사원등록 하러가기(form태그)
	//*** 연락처 tell input태그 3개를 어떻게 가져올 것인가?
	//우리가 넣어야할 방법은 010-3333-4444 이다
	//---- replace 함수 사용하기-------------------//
	@PostMapping("/regEmp")
	public String regEmp(EmpVO empVO) {
//		empVO.getTell(); // "010,1111,2222" 
//		String tell = empVO.getTell().replace(",", "-");
//		System.out.println(tell);//010,1111,2222 --> 010-1111-2222
//		empVO.setTell(tell);
		
		//요약하여 한줄로 만들기
		empVO.setTell(empVO.getTell().replace(",", "-"));
		
		empService.insertEmp(empVO);
		return "redirect:/emp/list";
	}
	
	//사원목록
	@GetMapping("/list")
	public String list(Model model) {
		model.addAttribute("empList", empService.selectEmp());
		return "content/list";
	}
	
}
  • EmpServiceImpl
package kh.study.emp.emp.service;

@Service("empService")
public class EmpServiceImpl implements EmpService{
	@Autowired
	private SqlSessionTemplate sqlSession;
	@Override
	public void insertEmp(EmpVO empVO) {
		sqlSession.insert("empMapper.insertEmp", empVO);
	}
	@Override
	public List<EmpVO> selectEmp( ) {
		return sqlSession.selectList("empMapper.selectEmp");
	}
}
  • EmpVO
package kh.study.emp.emp.vo;

@Getter
@Setter
@ToString
public class EmpVO {
		
	private String	empNo;
	private String	empName;
	private String	job;
	private int	age;
	private String	gender;
	private String	tell;
	private String	deptNo;
	//association 이용
	private DeptVO	deptInfo;
}

패키지 이외 파일 생성


mapper

point!

  • 사실 mapper는 하나의 파일로 만들고 그 안에 resultmap을 두개 생성해서 dept와 emp mapper를 생성해서 사용할 수 있는 방법도 있고 아래처럼 두개의 각각의 mapper를 생성해도 무방하다.
  • 하지만 '사원목록조회 화면 만들기'에서 사원정보 테이블(emp)와 부서정보 테이블 (dept)를 하나의 테이블처럼 사용해서 목록을 조회해야하는데, 이 때 방법이 여러가지가 있다.
    : join,association(1:1),collection(1:N),view,resultmap에 바로 추가하기..등등
  • 우리는 association을 사용하여 사원목록조회를 했다.
  • 여기서 왜 association을 선택하는가?
    : 사실 어떤 테이블을 기준으로 두는가에 따라 association,collection 모두 가능하다.
    사원을 기준시, 하나의 사원은 하나의 부서를 갖기때문에 association, 부서를 기준시, 하나의 부서는 여러명의 사원을 갖기때문에 collection 사용하면 둘 다 사용가능하게 된다.
    하지만 보통은 대개 FK,외래키를 갖는 테이블을 기준으로 사용한다. 따라서 EMP사원테이블 기준으로 하게되면 1:1 association 을 사용한다.
  • 그런데, 위에서 처럼 하나의 매퍼를 사용할 때와 각각의 매퍼를 두고 사용하게 될 때 차이가 있어 주의할 점이 있다.
    • resultMap의 값을 deptMapper의 id값을 가져와야하기때문에 id값뿐만아니라 해당 mapper의 namespace값.id값 으로 가져와야한다!
      • 각각의 매퍼 사용시: <association property="deptInfo" resultMap="deptMapper.dept"/>
      • 하나의 매퍼 사용시: <association property="deptInfo" resultMap="dept"/>
  • dept-mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="deptMapper">
 <resultMap type="kh.study.emp.dept.vo.DeptVO" id="dept">
	<id column="DEPT_NO" property="deptNo"/>
	<result column="DEPT_NAME" property="deptName"/>
	<result column="LOC" property="loc"/>
</resultMap> 

<!--목록조회 -->
<select id="selectDept" resultMap="dept">
SELECT DEPT_NO
, DEPT_NAME
, LOC
FROM TEST_DEPARTMENT
ORDER BY DEPT_NO
</select> 

<!-- 부서등록 -->
<!-- 1씩증가하는 다음 dept_no조회하기 dept001,dept002... -->
<!-- 실제로 내가 insert하기전에 selectKey를 먼저 조회 후
     string 문자열 자료형으로 이름은 keyProperty값으로 데리고 와서 사용하는데 순서를 쿼리실행 전 먼저 셀렉트키를 실행한다. -->
<insert id="insetDept">
	<selectKey resultType="String" keyProperty="deptNo" order="BEFORE">
		SELECT 'DEPT' || TO_CHAR(LPAD(NVL(MAX(TO_NUMBER(SUBSTR(DEPT_NO,5))),0)+1,3,'0'))
 		FROM TEST_DEPARTMENT	
	</selectKey>
	INSERT INTO TEST_DEPARTMENT (
		DEPT_NO
		, DEPT_NAME
		, LOC
	) VALUES (
		#{deptNo}
		, #{deptName}
		, #{loc}
	)
</insert>
</mapper>
  • emp-mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="empMapper">
<resultMap type="kh.study.emp.emp.vo.EmpVO" id="emp">
	<id column="EMP_NO" property="empNo"/>
	<result column="EMP_NAME" property="empName"/>
	<result column="JOB" property="job"/>
	<result column="AGE" property="age"/>
	<result column="GENDER" property="gender"/>
	<result column="TELL" property="tell"/>
	<result column="DEPT_NO" property="deptNo"/>
	<association property="deptInfo" resultMap="deptMapper.dept"/>
</resultMap>  
	<!-- 1:1 부서정보 : 사원정보 관계 (기본적으로 fk외래키가 있는 테이블 기준!!) -->
	<!-- deptMapper(namespace값)에 있는 dept 를 불러와야한다!! -->


<!-- 사원 등록 -->
<insert id="insertEmp">
	<selectKey resultType="String" keyProperty="empNo" order="BEFORE">
		SELECT 'EMP' || TO_CHAR(LPAD(NVL(MAX(TO_NUMBER(SUBSTR(EMP_NO,5))),0)+1,3,'0'))
 		FROM TEST_EMP	
	</selectKey>
	INSERT INTO TEST_EMP (
		EMP_NO
		,EMP_NAME
		,JOB
		,AGE
		,GENDER
		,TELL
		,DEPT_NO
	) VALUES (
		#{empNo}
		, #{empName}
		, #{job}
		, #{age}
		, #{gender}
		, #{tell}
		, #{deptNo}
	)
</insert>

<!--사원 및 부서 목록조회 (조인)-->
<select id="selectEmp" resultMap="emp">
SELECT  EMP_NO
		, EMP_NAME
		, TELL
		, AGE
		, GENDER
		, DEPT_NAME
		, LOC
FROM TEST_EMP  ,TEST_DEPARTMENT 
WHERE TEST_EMP.DEPT_NO = TEST_DEPARTMENT.DEPT_NO
ORDER BY EMP_NAME ASC
</select>  
</mapper>

layout

  • base_layout.html
    : 우리가 눈으로 보여지는 화면을 어떻게 영역을 나누어 화면을 구성하는지 정하는 파일(레이아웃)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
<th:block layout:fragment="css"></th:block><!-- 계속바뀌는 영역마다 css적용되는 부분 -->

</head>
<body>
<div class="container"><!-- 부트스트랩사용하라면 클래스명 콘테이너 적어야함!! -->
	<div class="row">
		<div class="col">
			<div th:replace="fragment/top::topFragment"></div>
		</div>
	</div>
	<div class="row">
		<div class="col">
			<div layout:fragment="content"></div>
		</div>
	</div>
	
</div>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8" crossorigin="anonymous"></script>

</body>
</html>

fragment

  • top.html
    : 홈/부서관리/사원등록/사원목록 -> 메뉴가 보이는 파일
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div th:fragment="topFragment">
	<th:block>
		<link rel="stylesheet" th:href="@{/css/menu.css}">
	</th:block>
	<div style="margin-top: 50px; margin-bottom: 50px;" class="row-12">
		<ul class="nav nav-pills nav-fill">
		  <li class="nav-item">
		    <a th:href="@{/emp/home}" class="nav-link active" aria-current="page" href="#">HOME</a>
		  </li>
		  <li class="nav-item">
		    <a th:href="@{/dept/manage}" class="nav-link" href="#">MANAGE_DEPT</a>
		  </li>
		  <li class="nav-item">
		    <a th:href="@{/emp/regEmp}" class="nav-link" href="#">REG_EMP</a>
		  </li>
		  <li class="nav-item">
		    <a th:href="@{/emp/list}" class="nav-link" href="#">LIST_EMP</a>
		  </li>
		</ul>
	</div>
</div>
</html>

content

  • home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout" 
	layout:decorate="~{layout/base_layout}">

<!-- 계속바뀌는 fragmnet페이지마다 적용되는 css가 다르기때문에 별도로 각각css불러와서 사용해야한다 -->
<!-- 홈화면 스타일 적용 -->
	<!-- 외부css파일불러오기 -->
<th:block layout:fragment="css">
<!--<link rel="stylesheet" th:href="@{/css/menu.css}"> -->
</th:block>
	
<div layout:fragment="content">
		<h1>사원관리 시스템</h1>
</div>
</html>
  • list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout" 
	layout:decorate="~{layout/base_layout}">

<!-- 계속바뀌는 fragmnet페이지마다 적용되는 css가 다르기때문에 별도로 각각css불러와서 사용해야한다 -->
<!-- 홈화면 스타일 적용 -->
	<!-- 외부css파일불러오기 -->
<th:block layout:fragment="css">
<!--<link rel="stylesheet" th:href="@{/css/menu.css}"> -->
</th:block>
	
<div layout:fragment="content">
		<h1>사원관리 시스템</h1>
</div>
</html>
  • manage.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout" 
	layout:decorate="~{layout/base_layout}">
<th:block layout:fragment="css">
	<link rel="stylesheet" th:href="@{/css/menu.css}">
</th:block>
	
<div align="center" layout:fragment="content">
	
	
	<div  class="row">
		<div class="col">
			<form th:action="@{/dept/regDept}" method="post" th:object="${deptVO}">
				<div class="col-12" align="left">
					- 부서등록
				</div>
				<div class="col" align="left">
				<div>
					<span>부서명</span>
					<span><input class="form-control" th:field="*{deptName}" type="text"></span>
				</div>
				<div>
					<span>지역</span>
					<span>
						<select th:field="*{loc}" class="form-control">
							<option value="부산" selected>부산</option>
							<option value="대구">대구</option>
							<option value="대전" >대전</option>
							<option value="서울" >서울</option>
							<option value="인천" >인천</option>
						</select>
					</span>
				</div>
				</div>
				<div align="center">
					<button type="submit">등록</button>
				</div>
			</form>
		</div>
	</div>
	
	
	
	
	<div class="row ">
		<div class="col">
			<div align="left">
			- 부서목록
			</div>
			<div>
			<!-- 테이블에다가 클래스값 아래와 같이 값주면 테이블디자인 적용됨 -->
				<table class="table table-striped table-hover" >
					<tr>
					<!-- th(thead)는 제목줄로 인식해서 자동정렬,굵게 자동생성!! -->
						<th>부서번호</th>
						<th>부서명</th>
						<th>지역</th>
					</tr>
					<tbody>
					<!-- 컨트롤러에서 dept 객체던지면 이값이 있냐 없냐에 따라 목록조회 -->
					<!-- deptList 데이더 가져오는 방법 2가지가 있다 -->
						<!-- 1번) <th:block th:if="${deptList != null}"> -->
						<!-- 2번) -->
						<th:block th:if="${#lists.size(deptList) != 0}">
							<tr th:each="dept : ${deptList}">
									<td th:text="${dept.deptNo}"></td>
									<td th:text="${dept.deptName}"></td>
									<td th:text="${dept.loc}"></td>
							</tr>
							</th:block>
						</th:block>	
						<th:block th:unless="${#lists.size(deptList) != 0}">
						<!-- <th:block th:unless="${deptList != null}"> -->
							<td colspan="3">조회된 게시글이 없습니다.</td>
						</th:block>
					</tbody>
				</table>
			</div>
		</div>
	</div>
</div>
</html>
  • reg.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout" 
	layout:decorate="~{layout/base_layout}">
<th:block layout:fragment="css">
	<link rel="stylesheet" th:href="@{/css/menu.css}">
</th:block>
	
<div layout:fragment="content">
<form class="row g-3" th:action="@{/emp/regEmp}" method="post" th:object="${empVO}">
  <div class="row justify-center-center"> 
	  <div class="col-12">
	    <label for="inputEmail4" class="form-label">사원명</label>
	    <input th:field="*{empName}" type="text" class="form-control"  placeholder="사원명을 입력하세요">
	  </div>
	  
	  <div class="col-md-6">
	    <label for="inputPassword4" class="form-label">직급</label>
		<select th:field="*{job}" type="text" class="form-select" >
	    	<option selected value="사원">사원</option>
	    	<option value="대리">대리</option>
	    	<option value="과장">과장</option>
	    	<option value="부장">부장</option>
	    </select>  
	  </div>
	  
	  
	  <div class="col-6">
	    <label for="inputEmail3" class="col-sm-4 col-form-label">부서</label>
        <select id="inputState" class="form-select" name="deptNo">
           <th:block th:each="dept : ${deptList}">
              <option th:text="${dept.deptName}" th:value="${dept.deptNo}"></option>
           </th:block>
	    </select>
	  </div>
	  
	<div class="row mb-3">
	  <div class="col-3">
	      <label for="inputAddress2" class="form-label">성별</label>
		  <div class="form-check">
			  <input value="Female" class="form-check-input" type="radio" name="gender"  checked>
			  <label class="form-check-label" for="flexRadioDefault1">Female</label>
		  </div>
      </div>
      <div class="col-3">
          <label for="inputEmail3" class="col-sm-4 col-form-label">&nbsp;</label>
		  <div class="form-check">
			  <input value="Male" class="form-check-input" type="radio" name="gender"  >
			  <label class="form-check-label" for="flexRadioDefault2">Male</label>
		  </div>
	  </div>
     </div>
	
	  <div class="col-6">
	    <label for="inputCity" class="form-label">나이</label>
	    <input th:field="*{age}" type="number" min="19" max="60" class="form-select"  >
	  </div>
	  
	  <div class="col-12">
	    <label for="inputState" class="form-label">연락처</label>
	  </div>
	  <div class="col-4">
	      <input type="text" name="tell" class="form-control" >
	  </div>
	  <div class="col-4">
	     <input type="text" name="tell" class="form-control"  >
	  </div>
	  <div class="col-4">
	     <input type="text" name="tell" class="form-control" >
	  </div>
	  <div class="col-12" align="center">
	    <button type="submit" class="btn btn-primary">Sign in</button>
	  </div>
  </div>
</form>
</div>
</html>

css

  • menu.css
    : top에 있는 메뉴들을 클릭시, 바뀌는 페이지마다 적용되는 css
    : ex) 사원목록페이지와 홈 페이지의 화면구성이나 폰트 혹은 컬러를 다르게 주고 싶을 때는 다른 css파일을 생성하여 적용시킬 수 있다. -> list.css,home.css...
/* top에 적용되는 css */
@charset "UTF-8";
@font-face {
    font-family: 'RIDIBatang';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_twelve@1.0/RIDIBatang.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}
body {
    font-family: 'RIDIBatang';
	font-size: 30px;
	text-align: center;
}


결과

  1. 홈화면

  2. 부서관리 화면

  3. 사원등록 화면

  4. 사원목록 화면

profile
Dev.Vinch

0개의 댓글