티스토리 뷰

[ 1. FrontController 패턴 - command에 따라서 다르게 실행 ] (**)

 

package org.zerock.myapp;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor

@WebServlet("*.do") // 다른 서블릿이 *.do로 매핑하고 있으면 오류발생할 수 있다.
public class FrontControllerServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		
		log.trace("service(req, res) invoked.");
		
		// =======================================
		
		String contextPath = req.getContextPath();
		String requestURI = req.getRequestURI();
		String requestURL = req.getRequestURL().toString();
		
		// =======================================
		
		log.info("\t + 0. contextPath : {}", contextPath); // /maven01 or /myapp
		
		// + contextPath가 그냥 /(루트)일 경우 빈문자열이기에, 출력되지 않는다.
		// + 즉 그냥 루트일 경우에는 substring할 필요 없이 URI를 사용하면 된다.
		
		// =======================================
		
		log.info("\t + 1. requestURI : {}", requestURI); // /*.do
		log.info("\t + 2. requestURL : {}", requestURL); // http://localhost:8080/*.do
		
		// 현재 모든 URL 중 .do로 끝나는 모든 요청을 여기에 집중시키고 있다.
		
		// =======================================
		
		// substring으로 URI에서 컨텍스트 페스를 제외한 문자열을 돌려준다.
		// String command = requestURI.substring(contextPath.length());
		
		String command = requestURI;
		log.info("\t + 3. command : {}", command); // /*.do
		
		// + command는 contextPath가 그냥 루트일 경우 URI와 동일하게 나온다.
		
		// =======================================
		
		// command에 따라서 로그가 다르게 찍힌다.
		
		switch( command ) {
		
			case "/insert.do":
				log.info("\t + 4. insert request.");
				break;
				
			case "/update.do":
				log.info("\t + 4. update request.");
				break;
				
			case "/delete.do":
				log.info("\t + 4. delete request.");
				break;
				
			case "/select.do":
				log.info("\t + 4. select request.");
				break;
		
		} // switch
		
		// =======================================
		
	} // service

} // end class

[ 2. Command 패턴 - command에 따라서 다르게 실행 ] (****)

 

[ 2 - 1. EmpVO 생성 : 데이터 베이스에서 앞으로 가지고 올때 사용, 읽기 전용 - 주고  ]

 

package org.zerock.myapp.domain;

import lombok.Value;


// + getter / setter 롬복
//@Getter @Setter

// + 생성자 롬복
//@NoArgsConstructor
//@AllArgsConstructor

// + Data 롬복으로 getter, setter, 매개변수가 없는 생성자를 한번에 만들 수 있다. + @toString
// + @Data는 DTO 패턴에서 사용된다. (***)
//@Data

// + VO패턴에서는 읽기 전용이기에, @Value를 통해서 읽기는 가능하지만, 수정은 못하도록 해야 한다. 
// + @Value는 VO패턴에서 사용된다. (***)
@Value
public class EmpVO {
	
	private Integer empno;			// PK
	private String ename;			// NULL 허용
	private Double sal;				// NULL 허용
	private Integer deptno;			// NULL 허용
	
	// NULL을 포함해야 될 때에는 기본타입이 아닌 Wrapper(참조) 타입을 사용해야 한다. (***)

} // end class

 

[ 2 - 2. EmpDTO 생성 : 사용자가 입력한 값을 뒤로 보내준다, CRUD할 수 있다. - 받고  ]

 

package org.zerock.myapp.domain;

import lombok.Data;

@Data // @Data = DTO, @Value = VO
public class EmpDTO {
	
	// DTO는 화면에서 입력한 값을 뒤로 보내준다.
	
	private Integer empno;			// PK
	private String ename;			// NULL 허용
	private Double sal;				// NULL 허용
	private Integer deptno;			// NULL 허용

} // end class

 

[ 2 - 3. Service 인터페이스 생성 : 제공할 Service의 틀을 잡는다.  ]

 

package org.zerock.myapp.service;

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

import org.zerock.myapp.exception.BizProcessException;


public interface Service {
	
	public static final String BIZ_RESULT = "__RESULT__";
	
	public static final String DTO = "__DTO__";
	
	// + 서비스에 따라서 되돌려주는 값이 달라질 수 있기에 Object타입으로 만들었다.
	
	public abstract void execute (HttpServletRequest req, HttpServletResponse res) throws BizProcessException;

} // end interface

 

[ + 전용 예외 클래스 만들기 ]

 

package org.zerock.myapp.exception;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class BizProcessException extends Exception {

	private static final long serialVersionUID = 1L;
	
	public BizProcessException(String msg) {
		
		super(msg); // 부모에게 메세지 날린다.
		
	} // constructor : 메세지
	
	public BizProcessException(Exception e) {
		
		super(e); // 예외를 부모에게 넘겨준다.
		
	} // constructor2 : 예외

} // end class

 

[ 2 - 4. Service 인터페이스 상속받는 service 생성 : 제공할 Service를 생성한다.  ]

 

[ 1 ) Select Service : 조회 전용 ]

 

package org.zerock.myapp.service;

import java.sql.SQLException;
import java.util.List;

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

import org.zerock.myapp.domain.EmpVO;
import org.zerock.myapp.exception.BizProcessException;
import org.zerock.myapp.persistence.EmpDAO;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor
// select.do 요청을 실제 처리할 비지니스 로직
public class SelectService implements Service {

	@Override
	public void execute(HttpServletRequest req, HttpServletResponse res) throws BizProcessException {
		
		log.trace("execute(req, res) invoked.");
		
		// =======================================
		// 실제 로직
		// =======================================
		
		try {
			
			// 영속계층에서 데이터를 가지고 오는 DAO객체 생성
			EmpDAO dao = new EmpDAO();
			
			// + dao의 selectAll메소드를 한 결과를 반환한다.
			// + 즉, sql문대로 실행한 결과를 List<EmpVO>타입으로 반환한다.
			
			// 비지니스 수행결과 데이터 발생
			List<EmpVO> list = dao.selectAll();
			
			// 공유데이터 영역에 비지니스 제이터를 속성 바인딩시킨다.
			ServletContext sc = req.getServletContext();	// Application scope 객체
			sc.setAttribute(Service.BIZ_RESULT, list); // 인터페이스에서 정적객체 가지고 오기
			
		} catch(SQLException e) {
			throw new BizProcessException(e);
		} // try - catch 
		
	} // execute

} // end class

 

 

[ 2 ) Insert Service : 삽입 전용 ]

 

package org.zerock.myapp.service;

import java.sql.SQLException;
import java.util.List;

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

import org.zerock.myapp.domain.EmpDTO;
import org.zerock.myapp.domain.EmpVO;
import org.zerock.myapp.exception.BizProcessException;
import org.zerock.myapp.persistence.EmpDAO;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor
public class InsertService implements Service {

	@Override
	public void execute(HttpServletRequest req, HttpServletResponse res) throws BizProcessException {
		
		log.trace("execute(req, res) invoked.");
		
		try {
			
			EmpDTO dto = (EmpDTO) req.getAttribute(Service.DTO);
			
			EmpDAO dao = new EmpDAO();
			
			int insertRows = dao.insert(dto);
			req.getServletContext().setAttribute(Service.BIZ_RESULT, insertRows);
			
			log.info("\t + insertRows : {}", insertRows);
			
		} catch(SQLException e) {
			throw new BizProcessException(e);
		} // try - catch 

	} // execute

} // end class

 

[ 3 ) Update Service : 수정 전용 ]

 

package org.zerock.myapp.service;

import java.sql.SQLException;
import java.util.List;

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

import org.zerock.myapp.domain.EmpDTO;
import org.zerock.myapp.domain.EmpVO;
import org.zerock.myapp.exception.BizProcessException;
import org.zerock.myapp.persistence.EmpDAO;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor
public class UpdateService implements Service {

	@Override
	public void execute(HttpServletRequest req, HttpServletResponse res) throws BizProcessException {
		
		log.trace("execute(req, res) invoked.");
		
		try {
			
			EmpDTO dto = (EmpDTO) req.getAttribute(Service.DTO);
			
			EmpDAO dao = new EmpDAO();
			
			int updateRows = dao.update(dto);
			req.getServletContext().setAttribute(Service.BIZ_RESULT, updateRows);
			
			log.info("\t + insertRows : {}", updateRows);
			
		} catch(SQLException e) {
			throw new BizProcessException(e);
		} // try - catch 

	} // execute

} // end class

 

[ 4 ) Delete Service : 삭제 전용 ]

 

package org.zerock.myapp.service;

import java.sql.SQLException;
import java.util.List;

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

import org.zerock.myapp.domain.EmpDTO;
import org.zerock.myapp.domain.EmpVO;
import org.zerock.myapp.exception.BizProcessException;
import org.zerock.myapp.persistence.EmpDAO;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor
public class DeleteService implements Service {

	@Override
	public void execute(HttpServletRequest req, HttpServletResponse res) throws BizProcessException {
		
		log.trace("execute(req, res) invoked.");
		
		try {
			
			EmpDTO dto = (EmpDTO) req.getAttribute(Service.DTO);
			
			EmpDAO dao = new EmpDAO();
			
			int deleteRows = dao.delete(dto);
			req.getServletContext().setAttribute(Service.BIZ_RESULT, deleteRows);
			
			log.info("\t + insertRows : {}", deleteRows);
			
		} catch(SQLException e) {
			throw new BizProcessException(e);
		} // try - catch 

	} // execute

} // end class

 

[ 5 ) Unknown Service : 지원되지 않는 서비스 ]

 

package org.zerock.myapp.service;

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

import org.zerock.myapp.exception.BizProcessException;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor

// 잘못된 요청(command)에 대한 처리를 수행하는 서비스 객체
public class UnknownReqService implements Service {

	@Override
	public void execute(HttpServletRequest req, HttpServletResponse res) throws BizProcessException {

		log.trace("execute(req, res) invoked.");
		
		ServletContext sc = req.getServletContext();	// Application scoe 객체
		sc.setAttribute(Service.BIZ_RESULT, "Bad Request"); // 인터페이스에서 정적객체 가지고 오기
		
	} // execute

} // UnknownReqService

 

[ 2 - 5. EmpDAO 생성 : 비지니스 로직 ]

 

package org.zerock.myapp.persistence;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.zerock.myapp.domain.EmpDTO;
import org.zerock.myapp.domain.EmpVO;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor
public class EmpDAO { // POJO : Plain Old Java Object
	
	// 서블릿이 아니면, 자동으로 JNDI Lookup할 수 없다. -> 수동으로 해야 한다.
	// @Resource(name="jdbc/OracleCloudATPWithDriverSpy")
	
	// + Servlet 클래스의 내부에서는 위의 어노테이션으로 자원객체를 JNDI tree로부터
	// + 얻어낼 수 있지만, 그 외의 클래스에서는 불가능하다. (***)
	
	// ====================================
	
	private static DataSource dataSource;
	
	// ====================================
	
	static { // JNDI Lookup을 해서, DataSource 객체의 주소를 획득
		
		try {
			
			Context ctx = new InitialContext();
			
			Object obj = ctx.lookup("java:comp/env/jdbc/OracleCloudATPWithDriverSpy");
			dataSource = (DataSource) obj;
			
		} catch (NamingException e) { ;; } // try - catch
		
	} // static initializer : 원래는 생성자 안에서 해야 한다.
	
	// ====================================
	
	public List<EmpVO> selectAll() throws SQLException {
		
		// selectAll() : 해당 테이터를 모두 선택해서 반환
		log.trace("select() invoked.");
		
		log.debug("\t + this.dataSource : {}", dataSource);
		
		List<EmpVO> list = new ArrayList<>();
		// EmpVO 객테타입을 보관하는 리스트(ArrayList)를 생성
		
		try {
			
			Connection conn = dataSource.getConnection();
			
			String sql = "SELECT empno, ename, sal, deptno FROM emp";
			
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			ResultSet rs = pstmt.executeQuery();
			
			try( conn; pstmt; rs; ) {
				
				while ( rs.next() ) {
					
					Integer empno = rs.getInt("empno");
					String ename = rs.getString("ename");
					Double sal = rs.getDouble("sal");
					Integer deptno = rs.getInt("deptno");
					
					// VO(값 객체)는 1개의 테이블의 1개의 레코드를 읽기 전용으로 보관하는 객체이다.
					
					EmpVO vo = new EmpVO(empno, ename, sal, deptno);
					// EmpVO 객체로 하나의 레코드의 값을 가지고 있는 객체를 생성한다. 
					
					list.add(vo);
					// EmpVO 객체를 리스트에 저장한다.
					
				} // while : 레코드 하나씩 빼오기
				
			} // try - with - resources
			
		} catch(Exception e) {
			throw new SQLException(e);
		} // try - catch
		
		return list;
		// EmpVO 객체를 보관하고 있는 리스트를 반환한다.
		
	} // selectAll - 모든 레코드를 반환
	
	// ====================================
	
	public int insert(EmpDTO dto) throws SQLException { 
		
		log.trace("insert({}) invoked.", dto);
		
		try {
			
			Connection conn = dataSource.getConnection();
			
			String sql = "INSERT INTO emp ( empno, ename, sal, deptno ) VALUES ( ?, ?, ?, ?)";
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, dto.getEmpno());
			pstmt.setString(2, dto.getEname());
			pstmt.setDouble(3, dto.getSal());
			pstmt.setInt(4, dto.getDeptno());
			
			
			// insert문은 영향을 받은 행의 수를 반환한다.
			int affectedLines = pstmt.executeUpdate();
			
			try( conn; pstmt; ) {
				
				return affectedLines;
				
			} // try - with - resources
			
		} catch(Exception e) {
			throw new SQLException(e);
		} // try - catch
		
	} // insert : 삽입문의 경우 삽입된 행의 수를 출력한다.
	
	// ====================================
	
	public int update(EmpDTO dto) throws SQLException { 
		
		log.trace("update({}) invoked.", dto);
		
		try {
			
			Connection conn = dataSource.getConnection();
			
			String sql = "DELETE FROM emp SET ename = ?, sal = ?, deptno = ? WHERE empno = ?";
			PreparedStatement pstmt = conn.prepareStatement(sql);

			pstmt.setString(1, dto.getEname());
			pstmt.setDouble(2, dto.getSal());
			pstmt.setInt(3, dto.getDeptno());
			pstmt.setInt(4, dto.getEmpno());
			
			// insert문은 영향을 받은 행의 수를 반환한다.
			int affectedLines = pstmt.executeUpdate();
			
			try( conn; pstmt; ) {
				
				return affectedLines;
				
			} // try - with - resources
			
		} catch(Exception e) {
			throw new SQLException(e);
		} // try - catch
		
	} // update : 수정문의 경우 수정된 행의 수를 출력한다.
	
	// ====================================
	
	public int delete(EmpDTO dto) throws SQLException { 
		
		log.trace("delete({}) invoked.", dto);
		
		try {
			
			Connection conn = dataSource.getConnection();
			
			String sql = "DELETE FROM emp WHERE empno = ?";
			PreparedStatement pstmt = conn.prepareStatement(sql);

			pstmt.setInt(1, dto.getEmpno());
			
			// insert문은 영향을 받은 행의 수를 반환한다.
			int affectedLines = pstmt.executeUpdate();
			
			try( conn; pstmt; ) {
				
				return affectedLines;
				
			} // try - with - resources
			
		} catch(Exception e) {
			throw new SQLException(e);
		} // try - catch
		
	} // delete : 삭제문의 경우 삭제된 행의 수를 출력한다.
	
	// ====================================

} // end class

 

[ 2 - 6. Servlet 생성 ]

 

package org.zerock.myapp;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.zerock.myapp.domain.EmpDTO;
import org.zerock.myapp.exception.BizProcessException;
import org.zerock.myapp.service.DeleteService;
import org.zerock.myapp.service.InsertService;
import org.zerock.myapp.service.SelectService;
import org.zerock.myapp.service.Service;
import org.zerock.myapp.service.UnknownReqService;
import org.zerock.myapp.service.UpdateService;

import lombok.Cleanup;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor

@WebServlet("*.do") // 다른 서블릿이 *.do로 매핑하고 있으면 오류발생할 수 있다.
public class FrontControllerServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		
		log.trace("service(req, res) invoked.");
		
		// =======================================
			// 1. ContextPath와 URL/URI(요청)확인
		// =======================================
		
		String contextPath = req.getContextPath();
		String requestURI = req.getRequestURI();
		String requestURL = req.getRequestURL().toString();
		
		// =======================================
		
		log.info("\t + 0. contextPath : {}", contextPath); // /maven01 or /myapp
		
		// + contextPath가 그냥 /(루트)일 경우 빈문자열이기에, 출력되지 않는다.
		// + 즉 그냥 루트일 경우에는 substring할 필요 없이 URI를 사용하면 된다.
		
		// =======================================
		
		log.info("\t + 1. requestURI : {}", requestURI); // /*.do
		log.info("\t + 2. requestURL : {}", requestURL); // http://localhost:8080/*.do
		
		// 현재 모든 URL 중 .do로 끝나는 모든 요청을 여기에 집중시키고 있다.
		
		// =======================================
		
		// substring으로 URI에서 컨텍스트 페스를 제외한 문자열을 돌려준다.
		// String command = requestURI.substring(contextPath.length());
		
		String command = requestURI;
		log.info("\t + 3. command : {}", command); // /*.do
		
		// + command는 contextPath가 그냥 루트일 경우 URI와 동일하게 나온다.
		
		// =======================================
			// 2. 전송파라미터를 DTO객체로 수집
		// =======================================
		
		String empno = req.getParameter("empno");
		String ename = req.getParameter("ename");
		String sal = req.getParameter("sal");
		String deptno = req.getParameter("deptno");
		
		// 수집된 각 전송 파라미터를 DTO 객체에 저장
		// DTO 객체는 웹3계층(표현/비지니스/영속 계층)의 뒤로 전달되면서 사용된다.
		EmpDTO dto = new EmpDTO();
		
		// null이 아니고 빈문자열도 아니어야 한다.
		if( empno != null && !"".equals(empno) ) { dto.setEmpno(Integer.parseInt(empno)); } // if - empno
		
		if( ename != null && !"".equals(ename) ) { dto.setEname(ename); } // if - ename
		
		if( sal != null && !"".equals(sal) ) { dto.setSal(Double.parseDouble(sal)); } // if - sal
		
		if( deptno != null && !"".equals(deptno) ) { dto.setDeptno(Integer.parseInt(deptno)); } // if - deptno
		
		// =======================================
			// 3. 요청 URI에 따라, command(요청유형) 결정
		// =======================================
		
		// Request Scope 공유 데이터 영역에 DTO 객체를 속성으로 바인딩
		// * 주의 * : 모든 Service 객체의 비지니스 로직 수행에 필요한 전송파라미터를
	    // 전달해주는 DTO 객체를, 또 다른 공유데이터 영역인 "Request Scope"을 통해 전달
	    // ( accessed by HttpServletRequest )

		// -> 비지니스 로직 수행에 필요한 데이터를 가지고 있는 것이 DTO 객체이기 때문에 이를 넘겨줘야 한다.
		
		req.setAttribute(Service.DTO, dto);
		
		// =======================================
		// 4. command 에 따라, 적합한 비지니스 서비스 객체 선택 및 비지니스 로직 수행
		// =======================================
		
		try {
			
			//  command(요청유형)에 따라, 각 요청을 처리하는 서비스 객체의 생성 및 비지니스 로직 수행(execute 메소드)
	        // * 주의 * : 비지니스 로직 수행 결과 데이터는, 공유데이터 영역인 "Application Scope"(accessed by ServletContext)에 바인딩
			
			switch( command ) {
			
			// 아래의 모든 service 객체에 필요한 전송파라미터를 전달해주는
			// DTO 객체는 3번째 공유데이터 영역인 Request Scope을 통해 전달된다.
			
				case "/insert.do":
					log.info("\t + 4. insert request.");
					new InsertService().execute(req, res); // 객체 생성 후 메소드 실행
					break;
					
				case "/update.do":
					log.info("\t + 4. update request.");
					new UpdateService().execute(req, res); // 객체 생성 후 메소드 실행
					break;
					
				case "/delete.do":
					log.info("\t + 4. delete request.");
					new DeleteService().execute(req, res); // 객체 생성 후 메소드 실행
					break;
					
				case "/select.do":
					log.info("\t + 4. select request.");
					new SelectService().execute(req, res); // 객체 생성 후 메소드 실행
					break;
					
				default : // == if-else
					log.info("\t + 4. unknown request.");
					new UnknownReqService().execute(req, res); // 객체 생성 후 메소드 실행
					break;
		
			} // switch
			
		} catch(BizProcessException e) {
			;;
		} // try - catch
		
		// =======================================
			// 응답 문서 준비
		// =======================================
		
		res.setContentType("text/html; charset=utf8");
		
		@Cleanup
		PrintWriter out = res.getWriter();
		out.println("<html><head></head><body>");
		
		// 위의 각 command 별로 수행되는 Service 개체의 execute 메소드의 수행결과를
		// 가지고 응답문서를 만들어 준다!
		
		ServletContext sc = req.getServletContext();
		Object bizResult = sc.getAttribute(Service.BIZ_RESULT);
		
		out.println("<p>" + bizResult + "</p>");
		
		out.println("</body></html>");
		out.flush();
		
	} // service

} // end class

 

[ 2 - 7. 화면 생성 ]

 

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FrontController 패턴 연습</title>
</head>

<body>

    <!-- 모두 .do로 끝나고 있다. -->
    <!-- 모두 실제로는 없는 파일들이다. -->

    <!-- 아래의 a태그의 경우 8090이라는 다른 사이트로 요청을 보냈으나, 없을 경우 연결되지 못한다. -->
    <a href="http://localhost:8090/08Chapter/up.do">수정하기</a><br>

    <a href="select.do">조회하기</a><br>
    <a href="insert.do?empno=1981&ename=ABCDEF&sal=10000&deptno=10">삽입하기</a><br>
    <a href="update.do?empno=1981&ename=ABCDEF&sal=20000&deptno=40">수정하기</a><br>
    <a href="delete.do?empno=1981">삭제하기</a><br>

    <!-- 링크는 단순히 이동하는 것이 아니라, GET 방식으로 요청을 보낸것이다. (***) -->
    <!-- <a href="https://www.naver.com/">NAVER</a><br> -->
    <!-- <a href="http://localhost:7000">NETCAT</a><br> -->

</body>

</html>
728x90
댓글
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
최근에 올라온 글
Total
Today
Yesterday
공지사항