-------------------------------------------------

1. 컨트롤러에 처리 하는 것 추가

 

@RequestMapping(value = "/sum.do", method = RequestMethod.GET)
public String sum(int num1, int num2, Model model) throws Exception {

model.addAttribute("sum", num1 + num2);
model.addAttribute("num1", num1); // 데이터 설정.....
model.addAttribute("num2", num2);

return "02.sumview"; // forward view
}

--------------------------------------------------------

2. 폼 페이지 추가 webapp 아래에

02.form.html 파일 생성후 아래의 코드 추가

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<!-- <form action="param.do" method="get" target="_blank"> -->
<form action="sum.do" method="get" target="myi">
<label>숫자1 </label> : 
<input type="number" name="num1"><br>
<label>숫자2 </label> : 
<input type="number" name="num2"><br>
<button>계산</button>
</form>

<iframe name="myi" width="100%" height="700" frameborder="0"></iframe>
</body>
</html>

 

---------------------------------------------------------------------

3. 뷰 페이지 추가

webapp - WEB-INF - jsp - egovframework - example 에

02.sumview.jsp 파일 생성후 아래의 코드 추가

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>숫자1 : ${num1}</h1>
<h1>숫자2 : ${num2}</h1>
<h1>합계 : ${sum}</h1>


</body>
</html>

 

---------------------------------------------------

4. 결과 확인

http://localhost:8086/ttt/02.form.html 주소창에 입력

 

 

 

작업환경 : 전자정부 프레임워크 4.0

오라클 11gex + sql developer

아파치톰캣 9.0

자바 JDK 18.0

 

------------------------------------------------------------------------------------

1. 전자정부 프레임워크 실행후

new - eGovFrame Web Project 각각 설정후 샘플파일 체크후 만들기

-----------------------------------------------------------------

2. pom.xml 에 오라클 드라이버 추가

        <!-- 오라클드라이버  -->
       <dependency>
         <groupId>com.oracle.database.jdbc</groupId>
         <artifactId>ojdbc6</artifactId>
         <version>11.2.0.4</version>
      </dependency>

-------------------------------------------------------

3. egovframework.example.sample.web에서

MyController.java 파일생성후 아래 작성

 

 

package egovframework.example.sample.web;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import test.my.mybean.MyData;


@Controller
public class MyController {





@RequestMapping(value = "/param.do", method = RequestMethod.GET)
public String param(HttpServletRequest request, Model model) throws Exception {

String myname = request.getParameter("myname");
String myage = request.getParameter("myage");

model.addAttribute("myname", myname); // 데이터 설정.....
model.addAttribute("myage", myage);



return "01.view"; //forward view
}

}

---------------------------------------------------------------------------

4. webapp 아래에

01.form.html 파일 생성후 아래코드 작성

 

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<!-- <form action="param.do" method="get" target="_blank"> -->
<form action="param.do" method="get" target="myi">
<label>이름 </label> : 
<input type="text" name="myname"><br>
<label>나이 </label> : 
<input type="number" name="myage"><br>
<button>확인</button>
</form>

<iframe name="myi" width="100%" height="700" frameborder="0"></iframe>
</body>
</html>

 

-----------------------------------------------------------------------

5. webapp-WEB-INF-jsp-egovframework-example에

01.view.jsp 파일 생성후 아래 코드 작성

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>이름 : ${myname}</h1>
<h1>나이 : ${myage}</h1>

</body>
</html>

 

-------------------------------------------------------------------------------------------

6. 서버 실행

http://localhost:8086/ttt/01.form.html 주소창에 입력

 

 

DAO = Data Access Object의 약어로 실질적으로 DB에 접근하는 객체
저수준의 로직과 고급 비즈니스 로직을 분리하고, 도메인 로직으로 부터 persistence mechanism을 숨기기 위해 사용한다.
1. 효율적인 커넥션 관리와 보안성 때문에 사용
2. persistence 계층이란 DB영구저장소에 데이터를 CRUD 하는 계층 
DB에 대한 접근을 담당 커넥션을 하나만 가져오고 커넥션을 가져온 객체가 모든 DB와의 연결을 하는것이 DAO이다.
DB에 대한 접근을 DAO가 담당하도록 하여 데이터 베이스 엑세스를 DAO에서만 하게 되면 다수의 원격 호출을 통한
오버헤드를 VO나 DTO를 통해 줄일 수 있고, 다수의 DB호출 문제를 해결할 수 있다.


커넥션풀 = 커넥션 객체를 미리 만들어 놓고 가져다 쓰고 반환하는 것 으로 웹서버가 DB와 연결하기 위해 매번 커넥션
객체를 생성하는 것을 해결하기 위해 나온 것이다.
커넥션풀은 커넥션을 또 만드는 오버헤드를 효율적으로 하기 위해 DB에 접속하는 객체를 전용으로 하나 만들고,
모든 페이지에서 그 객체를 호출해서 사용한다.


DTO와 VO = 계층간 데이터 교환을 위한 자바 빈즈 로써, DTO,(Data Transfer Object)는 VO(Value Object)로 바꿔 말할 수 있다.
여기서 계층이란, 컨트롤러, 뷰 비즈니스 계층, 퍼시스턴스 계층을 말한다.
VO는 DTO와 동일한 개념이지만, READ ONLY 속성을 가진다.
대표적인 DTO로는 폼 데이터 빈, 데이터베이스 테이블 빈 등이 있으며 각 폼 요소나 데이터 베이스 레코드 데이터를
매핑하기 위한 데이터 객체를 말한다.
즉, 폼 필드들의 이름을 그대로 가지고 있는 자바빈 객체를 폼 필드와 그대로 매핑하여 비즈니스 계층으로 보낼때 사용한다.
이런객체를 DTO 라고 부르며 VO 패턴이라고도 한다.
일반적인 DTO는 로직을 가지고 있지 않은 순수한 데이터 객체 이며 속성과 그 속성에 접근하기 위한 getter, setter 메소드만
가진 클래스를 말한다.
getter,setter외에 toString(), equals()등 Object 클래스 메소드 작성


DAO와 service의 차이
DAO는 단일 데이터 접근/갱신만 처리하지만, service는 여러 DAO를 호출하여 여러번의 데이터 접근/갱신 하고
그렇게 읽은 데이터에 대한 비즈니스 로직을 수행 하고 그것을 하나의(혹은 여러개의) 트랜잭션으로 묶는다.
만약 DAO와 Service 가 완전히 동일해진다면, 그것은 해당 비즈니스 로직이 단일 DB 접근으로 끝나기 때문이다.
DAO 메소드 하나에 다중 DB접근 로직이 들어갔고, Service 에서 단순히 그 DAO를 호출하는 역할만 한다면,
DAO 측의 모듈화가 제대로 되지 않은 접근 방식일 가능성이 높다.





MVC2 패턴 이란?
model, view, controller 세부분으로 코드를 나누어 개발
View 화면 출력부분 (jsp)
Model DB에 연동하는 부분
Controller View와 Model을 연결하는 부분(controller)

3가지 파일만 생성, 수정하여 웹페이지 하나를 구현해봄.
jsp, controller, xml
jsp는 서블릿으로 변환되어 실행됨

1. index.jsp 파일을 WEB-INF 아래에 생성. 화면출력 부분 view에 해당


이 상태로 서버를 런해도 404 오류가 뜬다.

index.jsp 파일에 직접 접근할 수는 없기때문, 그래서 Controller를 이용하여 접근해야함.

2. 모든 web application은 반드시 하나의 web.xml 파일을 가져야하고, WEB-INF폴더 아래에 있다.



URL패턴을 home.do로 두고 servlet class를 com.exam.controller 패키지 안의 HomeController 클래스로 설정

home.do 주소가 호출되었을때 com.exam.controller 패키지의 HomeController 클래스가 실행된것





3. java class를 생성. type을 HttpServlet으로 선택 controller.java 





getRequestDispatcher 메소드는 받은 요청을 처리한 후 View 페이지로 처리하기 위하여 사용되는 메소드

매개값으로 경로를 주고 forward 메소드를 사용하면 해당 경로의 페이지를 화면에 출력

4. 결과물


서버를 실행하고 웹에서 localhost/(프로젝트명)newdeal01/home.do 를 치면 index.jsp 페이지가 구현된다! ! !




DAO (Data Access Object)

실질적으로 DB에 접근하여 CRUD 등을 조작하는 기능 수행

Service와 DB를 연결하는 역할

효율적인 커넥션 관리와 보안성 때문에 사용함.





DTO (Data Transfer Object)

DTO는 그저 계층간 데이터 교환이 이루어 질 수 있도록 하는 객체

Service와 Controller 사이에서 사용하는 데이터 교환

Getter/Setter 메소드만 갖는다.



사례)

사용자가 입력한 데이터를 DB에 넣는 과정

사용자가 자신의 브라우저에서 데이터를 입력하여 form에 있는 데이터를 DTO에 넣어서 전송합니다.

해당 DTO를 받은 서버가 DAO를 이용하여 데이터베이스로 데이터를 집어넣습니다.



VO (Value Object)

VO도 DTO와 동일한 개념이다. 다만 DTO와의 차이는, DTO는 데이터를 계층간 교환(Transfer)하는데 의미가 있고, 

VO는 읽기만 가능한 read-only 속성을 가진 객체로서 데이터 그 자체에 의미를 두고 있다는 점이다.





DTO (Data Transfer Object)

▶ 데이터 교환을 하기 위해 사용하는 객체

▶ 로직을 가지지 않는 순수한 데이터 저장을 위한 클래스

▶ ▶ 데이터베이스의 테이블명과 컬럼을 그대로 이용

▶ ▶ getter & setter 만 가진 클래스



브라우저 : Form 데이터 → 컨트롤러에서 DTO로 데이터 받음 → DAO에서 DTO로 데이터베이스로 insert

브라우저 : 리스트 출력 ← 컨트롤러에서 DTO로 데이터 받음 ← DAO에서 DTO로 데이터베이스에서 select



VO (Value Object)

▶ VO는 값 그 자체를 표현하는 객체로 읽기 전용

▶ DTO와 유사하지만 DTO는 setter를 가지고 있어 값이 변할 수 있음



DAO (Data Access Object)

▶ 데이터베이스를 사용하기 위한 로직 & 비지니스 로직을 분리하기 위해 사용

▶ 스프링부트에서는 보통 @Repository 어노테이션을 사용


Service
Controller가 Request를 받으면 적절한 Service에 전달하고, 전달 받은 Service는 business logic을 처리한다.
Service가 DB에 DAO로 접근하고, 데이터를 DTO로 전달받은 다음, 데이터를 필요에 맞게 가공하여 반환한다.
 



DAO(Data Access Object)

- Database 접근을 위한 객체이다.

- Data 삽입(INSERT), 수정(UPDATE), 삭제(DELETE), 조회(SELECT)를 조작/수행한다.

- 보통 DB와 연결할 Connection까지 설정하는 경우가 많다.

 

DTO(Data Transfer Object)

- 일반적으로 DB(Database)에 접근한 뒤 가져오거나(SELECT) 삽입(INSERT)할 값들을 담기 위해서 만든다.

- 담긴 값들은 계층간 데이터 교환을 위해 쓰이는 자바빈즈(beans)이다. (계층의 예 : Controller, Service, View 등...)

- 보통 멤버변수는 DB 테이블의 컬럼들이며, getter와 setter를 갖는다.

 

VO(Value Object)

- DTO와 거의 유사하다. 차이점은 Read-Only라는 점이다.

- 특정 객체를 만들어 값을 전달하고자 할 때 사용된다.





DAO, DTO, Service

Spring Framework의 MVC에서 Model은 Service, DAO, DTO로 나눌 수 있다. 한 번 살펴보자.

DAO

Data Access Object의 줄임말이다. DB를 사용해 데이터를 조회하거나 조작하는 기능을 담당하는 것들을 DAO라고 부른다. domain logic (비즈니스 로직이나 DB와 관련없는 코드들)을 persistence mechanism과 분리하기 위해 사용한다. 

 
•persistence layer: Database에 data를 CRUD(Create, Read, Update, Drop)하는 계층

이렇게 따로 분리해놓는 이유는 HTTP Request를 Web Application이 받게 되면 Thread를 생성하게 되는데 비즈니스 로직이 DB로부터 데이터를 얻어오기 위해 매번 Driver를 로드하고 Connection 객체를 생성하게 되면 엄청 많은 커넥션이 일어나므로 DAO를 하나 만들어 DB 전용 객체로만 쓰는 것이다. 이러면 부담이 줄어들게 된다.

이 개념은 DBCP(Database Connection Pool)로부터 나왔다. WAS(Web Application Server)이 실행되면 일정량의 DB Connection 객체를 Pool에다 저장해 두고, HTTP Request에 따라 필요할 때마다 Pool에서 Connection 객체를 가져다 쓰고 반환하는 것이다. 아래 그림 1과 같다.




보통 connection pool은 요청으로 생기는 thread(thread도 pool을 만들수도 있다.)보다 적게 만든다. 왜냐면 모든 Request가 DB에 관련된 것은 아니기 때문이다.

 

그럼 Spring에서 DAO는 어떻게 만들까? 우선 Spring에서 Singleton 패턴을 권장한다는 것을 기억하자. Spring에서 관리되는 Singleton 패턴이라 하면 당연히 Bean이다. Spring에서 DAO는 @Repository annotation으로 정의한다. class 선언 시 바로 @Repository annotation을 사용해도 되지만 참조한 글에 따르면 메소드 헤더만 정의한 interface를 정의하고 이것을 구현한 class에 annotation을 붙여 사용한다고 한다. 이유는 interface로 구성하면 확장성과 유연성이 높아지기 때문이다. 참조한 글 외에도 여러 잘하는 프로그래머 글에서도 이 방법으로 구현하는 것 같으니 한 번 따라해보자.

UserDao.java


public interface UserDao {
    /**
     * user 테이블에서 모든 유저의 정보를 가져온다.
     * 
     * @return 모든 유저의 정보
     */
    public List<User> getUsers();
}




UserDaoImpl.java


@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public List<User> getUsers()
    {
        // 리스트 생성
        List<User> result = new ArrayList<User>();

        // 데이터베이스에서 유저 목록을 가져온다.
        result.add(...);
        ...

        return result;
    }
}




DTO

Data Transfer Object의 줄임말이다. VO(Value Object)라고도 표현하는데, 계층간 데이터 교환을 위한 자바빈즈(Java Beans)다.

이 객체는 데이터베이스 레코드의 데이터를 매핑하기 위한 데이터 객체를 말한다. DTO는 보통 로직을 가지고 있지 않고 data와 그 data에 접근을 위한 getter, setter만 가지고 있다.

정리하면 DTO는 Database에서 Data를 얻어 Service나 Controller 등으로 보낼 때 사용하는 객체를 말한다. 위 코드에서도 DAO가 Database로부터 Data를 얻은 뒤 List에 담아서 보내주고 있다. DTO는 아래 코드와 같이 쓰일 수 있다.



public class User {
    private String name;
    private int age;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void getAge() {
        return this.age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    @Override
    public String toString() {
        return "name='" + name + "', age=" + age;
    }
}



위와 같이 DTO는 데이터를 주고받을 포맷이라고 할 수 있다.

Service

마지막으로 Service에 대해서 살펴보자. Service는 비지니스 로직이 들어가는 부분이다. Controller가 Request를 받으면 적절한 Service에 전달하고, 전달 받은 Service는 비즈니스 로직을 처리한다. DAO로 데이터베이스를 접근하고, DTO로 데이터를 전달받은 다음, 적절한 처리를 해 반환한다. 아래 코드처럼 쓰일 수 있다.

public interface UserService {
    /**
     * 유저 정보를 텍스트 파일로 저장한다.
     * 
     * @param path 저장할 파일의 경로
     * @return 저장한 유저의 개수
     */
    public int saveUsersAsTextFile(String path);
}



@Service("userService")
public class UserServiceImpl implements UserService {
    private static final Logger LOGGER = Logger.getLogger("UserServiceImpl");

    @Autowired
    private UserDao userDao;

    @Override
    public int saveUsersAsTextFile(String path) {
        List<User> users = userDao.getUsers();

        // 비즈니스 로직
        try (FileOutputStream fileOutputStream = new FileOutputStream(path)) {
            StringBuilder result = new StringBuilder();
            for(User user : users) {
                result.append(user);
                result.append('\n');
            }

            fileOutputStream.write(result.toString().getBytes());
        } catch (IOException exception) {
            LOGGER.log(Level.SEVERE, "파일을 쓸 수 없습니다.");
            throw new IllegalStateException(String.format("Can't write a file. path: %s", path));
        }

        return users.size();
    }
}



위 코드는 DAO로부터 DTO 리스트를 받고, DTO의 리스트를 파일로 저장하는 코드이다. @Autowired annotation으로 userDao bean을 찾아서 연결한 것을 볼 수 있다. (Spring에서는 DI(Dependency Injection, 의존성 주입)이라고 한다.)

 

Controller에서 서비스 호출은 아래 코드처럼 쓰일 수 있다.




@Controller
public class MainController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/save/users", method = RequestMethod.GET)
    public ModelAndView saveUsers(ModelAndView mv) {
        // 유저를 얻어와서 텍스트 파일로 저장한다.
        int saveCount = userService.saveUsersAsTextFile("users.txt");

        // 뷰에서 결과를 보여주기 위해 저장한 개수를 뷰에 넘긴다.
        mv.addObject("saveCount", saveCount);
        mv.setViewName("saveUsersResultView");

        return mv;
    }
}


MVC2 패턴 이란?
model, view, controller 세부분으로 코드를 나누어 개발
View 화면 출력부분 (jsp)
Model DB에 연동하는 부분
Controller View와 Model을 연결하는 부분(controller)

3가지 파일만 생성, 수정하여 웹페이지 하나를 구현해봄.
jsp, controller, xml
jsp는 서블릿으로 변환되어 실행됨

1. index.jsp 파일을 WEB-INF 아래에 생성. 화면출력 부분 view에 해당

 

 

 

 

이 상태로 서버를 런해도 404 오류가 뜬다.

index.jsp 파일에 직접 접근할 수는 없기때문, 그래서 Controller를 이용하여 접근해야함.

 

 

2. 모든 web application은 반드시 하나의 web.xml 파일을 가져야하고, WEB-INF폴더 아래에 있다.

 

 

 

 

 

URL패턴을 home.do로 두고 servlet class를 com.exam.controller 패키지 안의 HomeController 클래스로 설정

home.do 주소가 호출되었을때 com.exam.controller 패키지의 HomeController 클래스가 실행된것





3. java class를 생성. type을 HttpServlet으로 선택 controller.java 

 

 

 

 

 

getRequestDispatcher 메소드는 받은 요청을 처리한 후 View 페이지로 처리하기 위하여 사용되는 메소드

매개값으로 경로를 주고 forward 메소드를 사용하면 해당 경로의 페이지를 화면에 출력

 

4. 결과물

 

 

 

 

서버를 실행하고 웹에서 localhost/(프로젝트명)newdeal01/home.do 를 치면 index.jsp 페이지가 구현된다! ! !

 

 

 

 

 

DAO (Data Access Object)

실질적으로 DB에 접근하여 CRUD 등을 조작하는 기능 수행

Service와 DB를 연결하는 역할

효율적인 커넥션 관리와 보안성 때문에 사용함.





DTO (Data Transfer Object)

DTO는 그저 계층간 데이터 교환이 이루어 질 수 있도록 하는 객체

Service와 Controller 사이에서 사용하는 데이터 교환

Getter/Setter 메소드만 갖는다.



사례)

사용자가 입력한 데이터를 DB에 넣는 과정

사용자가 자신의 브라우저에서 데이터를 입력하여 form에 있는 데이터를 DTO에 넣어서 전송합니다.

해당 DTO를 받은 서버가 DAO를 이용하여 데이터베이스로 데이터를 집어넣습니다.



VO (Value Object)

VO도 DTO와 동일한 개념이다. 다만 DTO와의 차이는, DTO는 데이터를 계층간 교환(Transfer)하는데 의미가 있고, 

VO는 읽기만 가능한 read-only 속성을 가진 객체로서 데이터 그 자체에 의미를 두고 있다는 점이다.

DAO = Data Access Object의 약어로 실질적으로 DB에 접근하는 객체
저수준의 로직과 고급 비즈니스 로직을 분리하고, 도메인 로직으로 부터 persistence mechanism을 숨기기 위해 사용한다.
1. 효율적인 커넥션 관리와 보안성 때문에 사용
2. persistence 계층이란 DB영구저장소에 데이터를 CRUD 하는 계층 
DB에 대한 접근을 담당 커넥션을 하나만 가져오고 커넥션을 가져온 객체가 모든 DB와의 연결을 하는것이 DAO이다.
DB에 대한 접근을 DAO가 담당하도록 하여 데이터 베이스 엑세스를 DAO에서만 하게 되면 다수의 원격 호출을 통한
오버헤드를 VO나 DTO를 통해 줄일 수 있고, 다수의 DB호출 문제를 해결할 수 있다.


커넥션풀 = 커넥션 객체를 미리 만들어 놓고 가져다 쓰고 반환하는 것 으로 웹서버가 DB와 연결하기 위해 매번 커넥션
객체를 생성하는 것을 해결하기 위해 나온 것이다.
커넥션풀은 커넥션을 또 만드는 오버헤드를 효율적으로 하기 위해 DB에 접속하는 객체를 전용으로 하나 만들고,
모든 페이지에서 그 객체를 호출해서 사용한다.


DTO와 VO = 계층간 데이터 교환을 위한 자바 빈즈 로써, DTO,(Data Transfer Object)는 VO(Value Object)로 바꿔 말할 수 있다.
여기서 계층이란, 컨트롤러, 뷰 비즈니스 계층, 퍼시스턴스 계층을 말한다.
VO는 DTO와 동일한 개념이지만, READ ONLY 속성을 가진다.
대표적인 DTO로는 폼 데이터 빈, 데이터베이스 테이블 빈 등이 있으며 각 폼 요소나 데이터 베이스 레코드 데이터를
매핑하기 위한 데이터 객체를 말한다.
즉, 폼 필드들의 이름을 그대로 가지고 있는 자바빈 객체를 폼 필드와 그대로 매핑하여 비즈니스 계층으로 보낼때 사용한다.
이런객체를 DTO 라고 부르며 VO 패턴이라고도 한다.
일반적인 DTO는 로직을 가지고 있지 않은 순수한 데이터 객체 이며 속성과 그 속성에 접근하기 위한 getter, setter 메소드만
가진 클래스를 말한다.
getter,setter외에 toString(), equals()등 Object 클래스 메소드 작성


DAO와 service의 차이
DAO는 단일 데이터 접근/갱신만 처리하지만, service는 여러 DAO를 호출하여 여러번의 데이터 접근/갱신 하고
그렇게 읽은 데이터에 대한 비즈니스 로직을 수행 하고 그것을 하나의(혹은 여러개의) 트랜잭션으로 묶는다.
만약 DAO와 Service 가 완전히 동일해진다면, 그것은 해당 비즈니스 로직이 단일 DB 접근으로 끝나기 때문이다.
DAO 메소드 하나에 다중 DB접근 로직이 들어갔고, Service 에서 단순히 그 DAO를 호출하는 역할만 한다면,
DAO 측의 모듈화가 제대로 되지 않은 접근 방식일 가능성이 높다.

전자정부 프레임워크 게시판 만들기 연습 (6) 파일 업로드, 다운로드

 

1. pom.xml

=======================================

 

<!-- file upload -->
        <dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>

<!-- MultipartHttpServletRequset -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

 

=======================================

ㄴ 추가후 Maven 업데이트 꼭!!! 해주기

 

 

2. dispatcher-servlet.xml

==================================

 

<!-- 파일 업로드 설정 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000" />
<property name="maxInMemorySize" value="100000000" />
</bean>

 

==================================

 

 

3. testMapper.xml

===============================

 

<!-- 게시글 삽입 -->
<insert id="insertTest" parameterType="egovframework.example.ivory.vo.TestVo">
<![CDATA[
INSERT INTO test(testTitle, testContent, testName, testDate, fileName)
VALUES(#{testTitle},#{testContent},'ivory',now(),#{fileName})
]]>
</insert>

<!-- 게시글 수정 -->
<update id="updateTest" parameterType="egovframework.example.ivory.vo.TestVo">
UPDATE test SET
testTitle = #{testTitle}, testContent = #{testContent}, fileName = #{fileName}
WHERE testId = #{testId}
</update>

 

===============================

ㄴ 삽입,수정부분만 fileName 추가

 

4. TestVo.java 에 필드추가

===========================

 

import org.springframework.web.multipart.MultipartFile;

 

 

private String fileName;
private MultipartFile uploadFile;

 

 

=============================

ㄴ +getter , setter 추가해주기

 

5. testRegister.jsp

============================

<form id="form_test" action="insertTest.do" method="post" encType="multipart/form-data">
<table class="table table-bordered">
<tbody>
<tr>
<th>제목</th>
<td><input type="text" placeholder="제목을 입력하세요." name="testTitle" class="form-control" /></td>
</tr>
<tr>
<th>내용</th>
<td><textarea placeholder="내용을 입력하세요 ." name="testContent" class="form-control" style="height: 200px;"></textarea></td>
</tr>
<tr>
<th>첨부파일</th>
<td><input type="file" name="uploadFile"></td>
</tr>
<tr>
<td colspan="2">
<button id="btn_register" type="button" class="btn_register">등록</button>
<button id="btn_previous" type="button" class="btn_previous">이전</button>
</tr>

</tbody>
</table>
</form>

 

============================

ㄴ form에 encType="multipart/form-data" 추가, 첨부파일 input 추가

 

 

6. TestController.java

==========================

import java.io.File;

import java.util.UUID;

import org.springframework.web.multipart.MultipartFile;

import org.apache.commons.io.FilenameUtils;

 

 

 

 

 

 

// 글쓰기
@RequestMapping(value = "/insertTest.do")
public String write(@ModelAttribute("testVo") TestVo testVo) throws Exception {

// 파일 업로드 처리
String fileName = null;
MultipartFile uploadFile = testVo.getUploadFile();
if (!uploadFile.isEmpty()) {
String originalFileName = uploadFile.getOriginalFilename();
String ext = FilenameUtils.getExtension(originalFileName); // 확장자 구하기
UUID uuid = UUID.randomUUID(); // UUID 구하기
fileName = uuid + "." + ext;
uploadFile.transferTo(new File("C:\\upload\\" + fileName));

}

testVo.setFileName(fileName);

System.out.println(testVo.getFileName());

testService.insertTest(testVo);

return "redirect:testList.do";

}

// 글수정
@RequestMapping(value = "/updateTest.do")

public String updateTest(@ModelAttribute("testVo") TestVo testVo, HttpServletRequest request) throws Exception {

// 파일 업로드
String fileName = null;
MultipartFile uploadFile = testVo.getUploadFile();
if (!uploadFile.isEmpty()) {
String originalFileName = uploadFile.getOriginalFilename();
String ext = FilenameUtils.getExtension(originalFileName); // 확장자구하기
UUID uuid = UUID.randomUUID(); // uuid구하기
fileName = uuid + "." + ext;
uploadFile.transferTo(new File("C:\\upload\\" + fileName));
testVo.setFileName(fileName);
}else{
testService.updateTest(testVo);
return "redirect:testDetail.do?testId=" + testVo.getTestId();
}
testService.updateTest(testVo);
return "redirect:testDetail.do?testId=" + testVo.getTestId();
}

 

 

==========================

ㄴ  import 추가

 

 

 

7. FileDownloadController클래스 생성

============================

 

package egovframework.example.ivory.controller;


import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

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


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class FileDownloadController {


@RequestMapping(value = "fileDownload.do")
public void fileDownload(HttpServletRequest request, HttpServletResponse response) throws Exception {
String filename = request.getParameter("fileName");
String realFilename = "";
System.out.println(filename);

try {

String browser = request.getHeader("User-Agent");
// 파일 인코딩
if (browser.contains("MSIE") || browser.contains("Trident") || browser.contains("Chrome")) {
filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
} else {
filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
}

} catch (UnsupportedEncodingException e) {

System.out.println("UnsupportedEncodingException 발생");
}

realFilename = "C:\\upload\\" + filename;
System.out.println(realFilename);

File file = new File(realFilename);
if (!file.exists()) {
return;
}

// 파일명 지정
response.setContentType("application/octer-stream");
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

try {
OutputStream os = response.getOutputStream();
FileInputStream fis = new FileInputStream(realFilename);

int cnt = 0;
byte[] bytes = new byte[512];

while ((cnt = fis.read(bytes)) != -1) {
os.write(bytes, 0, cnt);
}


fis.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}

}
}

 

============================

 

 

 

8. testDetail.jsp

===========================

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board Detail</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
crossorigin="anonymous">
</head>
<body>
<br />
<h1 class="text-center">Board Detail</h1>
<br />
<br />
<div class="container">
<form action="updateTest.do" id="viewForm" method="post" encType="multipart/form-data">
<table class="table table-bordered">
<tbody>
<tr>
<th>글번호</th>
<td><input name="testId" type="text" value="${vo.testId}" class="form-control" readonly /></td>
</tr>
<tr>
<th>제목</th>
<td><input type="text" value="${vo.testTitle}" name="testTitle" class="form-control" /></td>
</tr>
<tr>
<th>내용</th>
<td><textarea name="testContent" class="form-control" style="height: 200px;">${vo.testContent}</textarea></td>
</tr>
<tr>
<c:if test="${vo.fileName ne null}">
<tr>
<th>다운로드</th>
<td><a href="fileDownload.do?fileName=${vo.fileName}">
<input type="text" id="filename" value="${vo.fileName}" name="fileName" class="form-control" readonly="readonly" /></a>
<button id="filedelete" type="button" class="btn_previous" style="float: right">파일삭제</button>
</tr>
</c:if>
</tr>
<tr>
<th>첨부파일</th>
<td><input type="file" name="uploadFile"></td>
</tr>
<tr>
<td colspan="2" style="text-align: right;">
<button id="btn_previous" type="button" class="btn_previous">이전</button>
<button id="btn_modify" type="button" class="btn_register">수정</button>
<button id="btn_delete" type="button" class="btn_delete">삭제</button>
</td>
</tr>
</tbody>
</table>
</form>
</div>

<!-- Latest compiled and minified JavaScript -->
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script type="text/javascript">
$(document).on('click', '#btn_modify', function(e) {
if (confirm("정말 수정하시겠습니까 ?") == true) {
$("#viewForm").submit();
} else {
return;
}
});
$(document).on('click', '#btn_delete', function(e) {

var testId = ${vo.testId};

if (confirm("정말 삭제하시겠습니까 ?") == true) {
$("#viewForm").attr("action", "deleteTest.do?testId="+testId);
$("#viewForm").submit();
} else {
return;
}
});

//이전 클릭 시 testList로 이동
$("#btn_previous").click(function previous() {
$(location).attr('href', 'testList.do');

});

$("#filedelete").click(function deletefile() {
$('#filename').val(null);

});
</script>
</body>
</html>

===========================

 

마찬가지로 form에 encType="multipart/form-data" 추가,
다운로드, 첨부파일 항목을 추가해주고 파일삭제버튼을 눌렀을때 작동할 script문을 추가해준다.

 

 

ㄴ 파일업로드 완료

 

 

 

 

ㄴ 파일 다운로드 완료

 

 

 

ㄴ C\upload 폴더에  저장된 파일모습

 

 

ㄴ DB에 저장된 파일 모습

전자정부 프레임워크 게시판 만들기 연습 (5) 페이징, 검색

Pagination과 Search 클래스 추가

 

1. vo/Pagination.java

===================================

 

package egovframework.example.ivory.vo;

public class Pagination {

private int listSize = 10; //초기값으로 한 페이지당 보여질 게시글 개수
private int rangeSize = 5; //초기값으로 페이지 범위에 보여질 페이지 개수

private int page; //현재 페이지 번호
private int range; //현재 페이지 범위
private int listCnt; //전체 게시글의 개수
private int pageCnt; //전체 페이지 범위의 개수
private int startPage; //각 페이지 범위 시작 번호
private int startList; //게시판 시작번호
private int endPage; //각 페이지 범위 끝 번호

private boolean prev; //이전페이지
private boolean next; //다음페이지

public int getListSize() {
return listSize;
}

public void setListSize(int listSize) {
this.listSize = listSize;
}

public int getRangeSize() {
return rangeSize;
}

public void setRangeSize(int rangeSize) {
this.rangeSize = rangeSize;
}

public int getPage() {
return page;
}

public void setPage(int page) {
this.page = page;
}

public int getRange() {
return range;
}

public void setRange(int range) {
this.range = range;
}

public int getListCnt() {
return listCnt;
}

public void setListCnt(int listCnt) {
this.listCnt = listCnt;
}

public int getPageCnt() {
return pageCnt;
}

public void setPageCnt(int pageCnt) {
this.pageCnt = pageCnt;
}

public int getStartPage() {
return startPage;
}

public void setStartPage(int startPage) {
this.startPage = startPage;
}

public int getStartList() {
return startList;
}

public void setStartList(int startList) {
this.startList = startList;
}

public int getEndPage() {
return endPage;
}


public void setEndPage(int endPage) {
this.endPage = endPage;
}


public boolean isPrev() {
return prev;
}

public void setPrev(boolean prev) {
this.prev = prev;

}

public boolean isNext() {
return next;
}


public void setNext(boolean next) {
this.next = next;
}


public void pageInfo(int page, int range, int listCnt){
//현재페이지
this.page = page;

//현재페이지 범위
this.range = range;

//게시글 개수
this.listCnt = listCnt;

//전체 페이지 개수
this.pageCnt = (int)Math.ceil(listCnt/listSize);

//시작페이지
this.startPage = (range - 1) * rangeSize + 1;

//끝페이지
this.endPage = range * rangeSize;

//게시판 시작 번호
this.startList = (page - 1) * listSize;

//이전 버튼 상태
this.prev = range == 1 ? false : true;

//다음 버튼 상태
this.next = endPage > pageCnt ? false : true;

if(this.endPage > this.pageCnt) {
this.endPage = this.pageCnt;
this.next = false;
}
}
}

 

==================================

 

 

2. vo/Search.java

====================================

 

package egovframework.example.ivory.vo;

public class Search extends Pagination {

private String searchType;
private String keyword;

public String getSearchType() {
return searchType;
}
public void setSearchType(String searchType) {
this.searchType = searchType;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}

}

====================================

 

 

3. testMapper.xml

==================================

<?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="egovframework.example.ivory.service.TestMapper">

<!-- 게시글 목록 조회 -->
<select id="selectTest" resultType="egovframework.example.ivory.vo.TestVo">
SELECT * FROM test
<where>
<if test="searchType=='testTitle' and keyword != null and keyword !=''">
AND testTitle like CONCAT('%',#{keyword},'%')
</if>
<if test="searchType=='testContent' and keyword != null and keyword !=''">
AND testContent like CONCAT('%',#{keyword},'%')
</if>
<if test="searchType=='testName' and keyword != null and keyword !=''">
AND testName like CONCAT('%',#{keyword},'%')
</if>
</where>
ORDER BY testId DESC
LIMIT #{startList}, #{listSize}
</select>


<!-- 게시글 갯수 -->
<select id="getBoardListCnt" resultType="Integer">
SELECT count(*) as listCnt
FROM test
<where>
<if test="keyword != null and keyword != ''">
<if test="searchType=='testTitle'">
AND testTitle like CONCAT('%',#{keyword},'%')
</if>
<if test="searchType=='testContent'">
AND testContent like CONCAT('%',#{keyword},'%')
</if>
<if test="searchType=='testName'">
AND testName like CONCAT('%',#{keyword},'%')
</if>
</if>
</where>
</select>

<!-- 게시글 상세보기 -->
<select id="selectDetail" parameterType="Integer" resultType="egovframework.example.ivory.vo.TestVo">
SELECT * FROM test
WHERE testId = #{testId}
</select>

<!-- 게시글 삽입 -->
<insert id="insertTest" parameterType="egovframework.example.ivory.vo.TestVo">
INSERT INTO test(testTitle, testContent, testName, testDate)
VALUES(#{testTitle},#{testContent},'ivory',now())
</insert>

 

********************** 오라클 코드 *************************

<!-- 게시글 삽입 -->
<insert id="insertTest" parameterType="egovframework.example.ivory.vo.TestVo">
INSERT INTO test(testId, testTitle, testContent, testName, testDate)
VALUES(TESTID.NEXTVAL,#{testTitle},#{testContent},'ivory',SYSDATE)
</insert>

 

****************************************************************

<!-- 게시글 수정 -->
<update id="updateTest" parameterType="egovframework.example.ivory.vo.TestVo">
UPDATE test SET
testTitle = #{testTitle}, testContent = #{testContent}
WHERE testId = #{testId}
</update>


<!-- 게시글 삭제 -->
<delete id="deleteTest" parameterType="Integer">
DELETE FROM test
WHERE testId = #{testId}
    </delete>

</mapper>

==================================

 

4. testController.java

============================

package egovframework.example.ivory.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import egovframework.example.ivory.service.TestService;
import egovframework.example.ivory.vo.Search;
import egovframework.example.ivory.vo.TestVo;


@Controller
public class TestController {

@Autowired
private TestService testService;

//글보기 조회
/* @RequestMapping(value="/testList.do")
public String testListDo(TestVo testVo, Model model) throws Exception{

model.addAttribute("list", testService.selectTest(testVo));

return "test/testList";
}



//글목록페이지
@RequestMapping(value="/testList.do")
public String testListDo(TestVo testVo, Model model) throws Exception{
model.addAttribute("list", testService.selectTest(testVo));
return "test/testList";
}
*/





//글목록페이지,페이징,검색
@RequestMapping(value="/testList.do")
public String testListDo(Model model
,@RequestParam(required=false,defaultValue="1")int page
,@RequestParam(required=false,defaultValue="1")int range
,@RequestParam(required=false,defaultValue="testTitle")String searchType
,@RequestParam(required=false)String keyword
,@ModelAttribute("search")Search search) throws Exception{

//검색
model.addAttribute("search", search);
search.setSearchType(searchType);
search.setKeyword(keyword);

//전체 개시글 개수
int listCnt = testService.getBoardListCnt(search);

//검색 후 페이지
search.pageInfo(page, range, listCnt);
//페이징
model.addAttribute("pagination", search);
//게시글 화면 출력
model.addAttribute("list", testService.selectTest(search));

//model.addAttribute("list", testService.selectTest(testVo));

return "test/testList";
}






//글 상세페이지
@RequestMapping(value="testDetail.do")
public String viewForm(Model model, HttpServletRequest request) throws Exception{
int testId = Integer.parseInt(request.getParameter("testId"));
TestVo testVo = testService.selectDetail(testId);
model.addAttribute("vo", testVo);
return "test/testDetail";

}

//글작성페이지
@RequestMapping(value="/testRegister.do")
public String testRegister(){
return "test/testRegister";
}


//글쓰기
@RequestMapping(value="/insertTest.do")
public String write(@ModelAttribute("testVo") TestVo testVo) throws Exception {
testService.insertTest(testVo);
return "redirect:testList.do";
}

//글수정

@RequestMapping(value="/updateTest.do")
public String updateTest(@ModelAttribute("testVo") TestVo testVo) throws Exception {
testService.updateTest(testVo);
return "redirect:testDetail.do?testId="+testVo.getTestId();
}

//글삭제
@RequestMapping(value="/deleteTest.do")
public String deleteTest(HttpServletRequest request) throws Exception {
int testId = Integer.parseInt(request.getParameter("testId"));
testService.deleteTest(testId);
return "redirect:testList.do";
}

}

============================

selectTest에 보내주는 객체가 다르니 참고!! (service,serviceImpl,dao.... 에 있는 메서드도 바꿔주어야함)

 

5. testService.java

==============================

package egovframework.example.ivory.service;

import java.util.List;

import egovframework.example.ivory.vo.TestVo;

import egovframework.example.ivory.vo.Search;

public interface TestService {

public List<TestVo> selectTest(Search search) throws Exception;


//public List<TestVo> selectTest(TestVo testVo) throws Exception;

public void insertTest(TestVo testVo) throws Exception;

public TestVo selectDetail(int testId) throws Exception;

public void updateTest(TestVo testVo) throws Exception;

public void deleteTest(int testId) throws Exception;



public int getBoardListCnt(Search search) throws Exception;



}

=============================

 

6. testServiceImpl.java

=============================

package egovframework.example.ivory.service.impl;

import java.util.List;

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


import egovframework.example.ivory.dao.TestDao;
import egovframework.example.ivory.service.TestService;
import egovframework.example.ivory.vo.TestVo;

import egovframework.example.ivory.vo.Search;


@Service
public class TestServiceImpl implements TestService{


@Autowired
private TestDao testDao;


/* @Override
public List<TestVo> selectTest(TestVo testVo) throws Exception {

return testDao.selectTest(testVo);
}*/


@Override
public List<TestVo> selectTest(Search search) throws Exception {
return testDao.selectTest(search);
}

@Override
public int getBoardListCnt(Search search) throws Exception {
return testDao.getBoardListCnt(search);
}





@Override
public void insertTest(TestVo testVo) throws Exception {
testDao.insertTest(testVo);
}

@Override
public TestVo selectDetail(int testId) throws Exception {
return testDao.selectDetail(testId);
}

@Override
public void updateTest(TestVo testVo) throws Exception {
testDao.updateTest(testVo);
}

@Override
public void deleteTest(int testId) throws Exception {
testDao.deleteTest(testId);
}



}

=============================

 

 

7. testDao.java

===============================

package egovframework.example.ivory.dao;

import java.util.List;


import egovframework.example.ivory.vo.TestVo;

import egovframework.example.ivory.vo.Search;


public interface TestDao {


public List<TestVo> selectTest(Search search) throws Exception;
// public List<TestVo> selectTest(TestVo testVo) throws Exception;




public void insertTest(TestVo testVo) throws Exception;

public TestVo selectDetail(int testId)throws Exception;

public void updateTest(TestVo testVo) throws Exception;

public void deleteTest(int testId) throws Exception;




public int getBoardListCnt(Search search) throws Exception;

}



===============================

 

 

8. testDaoImpl.java

============================

package egovframework.example.ivory.dao.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import egovframework.example.ivory.dao.TestDao;
import egovframework.example.ivory.service.TestMapper;
import egovframework.example.ivory.vo.TestVo;

import egovframework.example.ivory.vo.Search;

@Repository
public class TestDaoImpl implements TestDao {

@Autowired
private SqlSession sqlSession;

/* @Override
public List<TestVo> selectTest(TestVo testVo) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
return mapper.selectTest(testVo);
}*/

@Override
public List<TestVo> selectTest(Search search) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
return mapper.selectTest(search);
}




@Override
public void insertTest(TestVo testVo) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
mapper.insertTest(testVo);
}

@Override
public TestVo selectDetail(int testId) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
return mapper.selectDetail(testId);
}

@Override
public void updateTest(TestVo testVo) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
mapper.updateTest(testVo);
}

@Override
public void deleteTest(int testId) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
mapper.deleteTest(testId);
}


@Override
public int getBoardListCnt(Search search) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
return mapper.getBoardListCnt(search);
}



}

============================

 

9. TestMapper.java

============================

package egovframework.example.ivory.service;

import java.util.List;

import egovframework.example.ivory.vo.TestVo;

import egovframework.example.ivory.vo.Search;

//Mapper namespace 와 ID를 연결할 Interface 를 두어서 interface를 호출하는 방법.
//Mybatis 매핑XML에 기재된 SQL을 호출하기 위한 인터페이스이다.
//SQL id는 인터페이스에 정의된 메서드명과 동일하게 작성한다
public interface TestMapper {


//List<TestVo> selectTest(TestVo testVo) throws Exception;

public List<TestVo> selectTest(Search search) throws Exception;



public void insertTest(TestVo testVo) throws Exception;

public TestVo selectDetail(int testId) throws Exception;

public void updateTest(TestVo testVo) throws Exception;

public void deleteTest(int testId) throws Exception;



public int getBoardListCnt(Search search)throws Exception;

}

============================

 

10. testList.jsp

============================

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board List</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<style type="text/css">
a {
    text-decoration: auto;
}
.row>*{
    width:auto;
}
</style>
</head>
<body>
<br />
<h1 class="text-center">Board List</h1>
<br />
<br />
<div class="container">
<table class="table table-hover table-striped text-center"
style="border: 1px solid;">
<colgroup>
<col width="10%" />
<col width="50%" />
<col width="20%" />
<col width="20%" />
</colgroup>
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>등록일자</th>
</tr>
</thead>

<tbody>
<c:forEach items="${list }" var="result">
<tr>
<td>${result.testId}</td>
<td><a href="testDetail.do?testId=${result.testId}">${result.testTitle}</a></td>
<td>${result.testName}</td>
<td>${result.testDate}</td>
</tr>
</c:forEach>
</tbody>
</table>
<!-- pagination start -->
<div id="paginationBox" class="pagination1">
<ul class="pagination" style="justify-content: center;">

<c:if test="${pagination.prev}">
<li class="page-item"><a class="page-link" href="#"
onClick="fn_prev('${pagination.page}', '${pagination.range}', '${pagination.rangeSize}', '${pagination.listSize}'
,'${search.searchType}', '${search.keyword}')">이전</a></li>
</c:if>

<c:forEach begin="${pagination.startPage}" end="${pagination.endPage}" var="testId">
<li class="page-item <c:out value="${pagination.page == testId ? 'active' : ''}"/> ">
<a class="page-link" href="#"
onClick="fn_pagination('${testId}', '${pagination.range}', '${pagination.rangeSize}', '${pagination.listSize}'
,'${search.searchType}', '${search.keyword}')">
${testId}</a></li>
</c:forEach>


<c:if test="${pagination.next}">
<li class="page-item"><a class="page-link" href="#"
onClick="fn_next('${pagination.range}', '${pagination.range}', '${pagination.rangeSize}', '${pagination.listSize}'
,'${search.searchType}', '${search.keyword}')">다음</a></li>
</c:if>
</ul>
</div>
<!-- pagination end -->
<hr />


<a class="btn btn-outline-info" style="float: right" href="testRegister.do">글쓰기</a>

<!-- search start -->
<div class="form-group row">
<div class="w100" style="padding-right: 10px">
<select class="form-control form-control-sm" name="searchType" id="searchType">
<option value="testTitle">제목</option>
<option value="testContent">내용</option>
<option value="testName">작성자</option>
</select>
</div>
<div class="w300" style="padding-right: 10px">
<input type="text" class="form-control form-control-sm" name="keyword" id="keyword">
</div>
<div>
<button class="btn btn-sm btn-primary" name="btnSearch" id="btnSearch">검색</button>
</div>

</div>
<!-- search end -->

</div>
<br>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
crossorigin="anonymous"></script>

<script
src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"
integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU"
crossorigin="anonymous"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js"
integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj"
crossorigin="anonymous"></script>
</body>
<script type="text/javascript">


//이전 버튼 이벤트
//5개의 인자값을 가지고 이동 testList.do
//무조건 이전페이지 범위의 가장 앞 페이지로 이동
function fn_prev(page, range, rangeSize, listSize, searchType, keyword) {

var page = ((range - 2) * rangeSize) + 1;
var range = range - 1;


var url = "/testList.do";
url += "?page=" + page;
url += "&range=" + range;
url += "&listSize=" + listSize;
url += "&searchType=" + searchType;
url += "&keyword=" + keyword;
location.href = url;
}


//페이지 번호 클릭
    function fn_pagination(page, range, rangeSize, listSize, searchType, keyword) {

var url = "/testList.do";
url += "?page=" + page;
url += "&range=" + range;
url += "&listSize=" + listSize;
url += "&searchType=" + searchType;
url += "&keyword=" + keyword;

location.href = url;
}

//다음 버튼 이벤트
//다음 페이지 범위의 가장 앞 페이지로 이동
function fn_next(page, range, rangeSize, listSize, searchType, keyword) {
var page = parseInt((range * rangeSize)) + 1;
var range = parseInt(range) + 1;
var url = "/testList.do";
url += "?page=" + page;
url += "&range=" + range;
url += "&listSize=" + listSize;
url += "&searchType=" + searchType;
url += "&keyword=" + keyword;
location.href = url;
}

// 검색
$(document).on('click', '#btnSearch', function(e){
e.preventDefault();
var url = "/testList.do";
url += "?searchType=" + $('#searchType').val();
url += "&keyword=" + $('#keyword').val();
location.href = url;
console.log(url);
});

</script>
</html>

=============================

 

서버 재실행

 

 

 

ㄴ testList.jsp 메인 화면

 

ㄴ 페이지 번호 이동

 

 

ㄴ 다음 버튼 눌렀을때

 

 

ㄴ 제목을 테스트로 검색 했을때

 

 

 

 

ㄴ 내용을 '검색어' 로 했을때

 

 

ㄴ 작성자를 'ddd' 로 검색 했을때

전자정부 프레임워크 게시판 만들기 연습 (4) 글 상세보기, 수정, 삽입, 삭제

글 상세보기, 수정, 삽입, 삭제

 

1. testMapper.xml

==============================================

 

<?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="egovframework.example.ivory.service.TestMapper">


<!-- 게시글 목록 조회 -->
<select id="selectTest" resultType="egovframework.example.ivory.vo.TestVo">
SELECT * FROM test
ORDER BY testId DESC
</select>

<!-- 게시글 상세보기 -->
<select id="selectDetail" parameterType="Integer" resultType="egovframework.example.ivory.vo.TestVo">
SELECT * FROM test
WHERE testId = #{testId}
</select>


<!--  MariaDB 게시글 삽입 -->
<insert id="insertTest" parameterType="egovframework.example.ivory.vo.TestVo">
INSERT INTO test(testTitle, testContent, testName, testDate)
VALUES(#{testTitle},#{testContent},'ivory',now())
</insert>

 

********** 오라클 용 *************************

<!--  ORACLE 게시글 삽입 -->
<insert id="insertTest" parameterType="egovframework.example.ivory.vo.TestVo">
INSERT INTO test(testId, testTitle, testContent, testName, testDate)
VALUES(TESTID.NEXTVAL,#{testTitle},#{testContent},'ivory',SYSDATE)
</insert>

**********************************

<!-- 게시글 수정 -->
<update id="updateTest" parameterType="egovframework.example.ivory.vo.TestVo">
UPDATE test SET
testTitle = #{testTitle}, testContent = #{testContent}
WHERE testId = #{testId}
</update>

<!-- 게시글 삭제 -->
<delete id="deleteTest" parameterType="Integer">
DELETE FROM test
WHERE testId = #{testId}
</delete>


</mapper>

 

=============================================

 

 

2. testController.java

=============================================

 

package egovframework.example.ivory.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import egovframework.example.ivory.service.TestService;
import egovframework.example.ivory.vo.TestVo;

@Controller
public class TestController {

@Autowired
private TestService testService;

//글보기 조회
/* @RequestMapping(value="/testList.do")
public String testListDo(TestVo testVo, Model model) throws Exception{

model.addAttribute("list", testService.selectTest(testVo));

return "test/testList";
}*/



//글목록페이지
@RequestMapping(value="/testList.do")
public String testListDo(TestVo testVo, Model model) throws Exception{

model.addAttribute("list", testService.selectTest(testVo));
return "test/testList";
}


//글 상세페이지
@RequestMapping(value="testDetail.do")
public String viewForm(Model model, HttpServletRequest request) throws Exception{
int testId = Integer.parseInt(request.getParameter("testId"));
TestVo testVo = testService.selectDetail(testId);
model.addAttribute("vo", testVo);

return "test/testDetail";
}

//글작성페이지
@RequestMapping(value="/testRegister.do")
public String testRegister(){
return "test/testRegister";
}


//글쓰기
@RequestMapping(value="/insertTest.do")
public String write(@ModelAttribute("testVo") TestVo testVo) throws Exception {
testService.insertTest(testVo);
return "redirect:testList.do";
}


//글수정
@RequestMapping(value="/updateTest.do")
public String updateTest(@ModelAttribute("testVo") TestVo testVo) throws Exception {
testService.updateTest(testVo);
return "redirect:testDetail.do?testId="+testVo.getTestId();
}


//글삭제
@RequestMapping(value="/deleteTest.do")
public String deleteTest(HttpServletRequest request) throws Exception {
int testId = Integer.parseInt(request.getParameter("testId"));
testService.deleteTest(testId);
return "redirect:testList.do";
}

}



 

=============================================

 

 

 

3. testService.java

 

 

=============================================

 

package egovframework.example.ivory.service;

import java.util.List;

import egovframework.example.ivory.vo.TestVo;

public interface TestService {

public List<TestVo> selectTest(TestVo testVo) throws Exception;

public void insertTest(TestVo testVo) throws Exception;

public TestVo selectDetail(int testId) throws Exception;

public void updateTest(TestVo testVo) throws Exception;

public void deleteTest(int testId) throws Exception;

}

 

==============================================

 

 

4. testServiceImpl.java

===========================================

 

package egovframework.example.ivory.service.impl;

import java.util.List;

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


import egovframework.example.ivory.dao.TestDao;
import egovframework.example.ivory.service.TestService;
import egovframework.example.ivory.vo.TestVo;

@Service
public class TestServiceImpl implements TestService{


@Autowired
private TestDao testDao;

@Override
public List<TestVo> selectTest(TestVo testVo) throws Exception {

return testDao.selectTest(testVo);
}



@Override
public void insertTest(TestVo testVo) throws Exception {
testDao.insertTest(testVo);
}

@Override
public TestVo selectDetail(int testId) throws Exception {
return testDao.selectDetail(testId);
}

@Override
public void updateTest(TestVo testVo) throws Exception {
testDao.updateTest(testVo);
}

@Override
public void deleteTest(int testId) throws Exception {
testDao.deleteTest(testId);
}



}

 

==========================================

 

 

 

5.testDao.java

=========================================

 

package egovframework.example.ivory.dao;

import java.util.List;


import egovframework.example.ivory.vo.TestVo;


public interface TestDao {

public List<TestVo> selectTest(TestVo testVo) throws Exception;




public void insertTest(TestVo testVo) throws Exception;

public TestVo selectDetail(int testId)throws Exception;

public void updateTest(TestVo testVo) throws Exception;

public void deleteTest(int testId) throws Exception;


}

 

=========================================

 

 

6. testDaoImpl.java

=========================================

 

package egovframework.example.ivory.dao.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import egovframework.example.ivory.dao.TestDao;
import egovframework.example.ivory.service.TestMapper;
import egovframework.example.ivory.vo.TestVo;

@Repository
public class TestDaoImpl implements TestDao {

@Autowired
private SqlSession sqlSession;

@Override
public List<TestVo> selectTest(TestVo testVo) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
return mapper.selectTest(testVo);
}

@Override
public void insertTest(TestVo testVo) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
mapper.insertTest(testVo);
}

@Override
public TestVo selectDetail(int testId) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
return mapper.selectDetail(testId);
}

@Override
public void updateTest(TestVo testVo) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
mapper.updateTest(testVo);
}

@Override
public void deleteTest(int testId) throws Exception {
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
mapper.deleteTest(testId);
}
}


 

=========================================

 

 

7. testMapper.java

======================================

 

package egovframework.example.ivory.service;

import java.util.List;

import egovframework.example.ivory.vo.TestVo;
//Mapper namespace 와 ID를 연결할 Interface 를 두어서 interface를 호출하는 방법.
//Mybatis 매핑XML에 기재된 SQL을 호출하기 위한 인터페이스이다.
//SQL id는 인터페이스에 정의된 메서드명과 동일하게 작성한다
public interface TestMapper {


List<TestVo> selectTest(TestVo testVo) throws Exception;


public void insertTest(TestVo testVo) throws Exception;

public TestVo selectDetail(int testId) throws Exception;

public void updateTest(TestVo testVo) throws Exception;

public void deleteTest(int testId) throws Exception;

}

 

======================================

 

 

8. testList.jsp

=========================================

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board List</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<style type="text/css">
a{
 text-decoration: auto;
}
</style>
</head>
<body>
<br/>
<h1 class="text-center">Board List</h1>
<br/>
<br/>
<div class="container">
        <table class="table table-hover table-striped text-center" style="border:1px solid;">
<colgroup>
<col width="10%" />
<col width="50%" />
<col width="20%" />
<col width="20%" />
</colgroup>
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>등록일자</th>

</tr>
</thead>


<tbody>
<c:forEach items="${list}" var="result">
<tr>
<td>${result.testId}</td>
<td><a href="testDetail.do?testId=${result.testId}">${result.testTitle}</a></td>
<td>${result.testName}</td>
<td>${result.testDate}</td>
</tr>
</c:forEach>
</tbody>
</table>
<hr/>
<div>
<ul class="pagination justify-content-center">
<li><a href="#" style="margin-right:5px;" class="text-secondary">◀</a></li>
<li><a href="#" style="margin-right:5px;" class="text-secondary">1</a></li>
<li><a href="#" style="margin-right:5px;" class="text-secondary">2</a></li>
<li><a href="#" style="margin-right:5px;" class="text-secondary">3</a></li>
<li><a href="#" style="margin-right:5px;" class="text-secondary">4</a></li>
<li><a href="#" style="margin-right:5px;" class="text-secondary">5</a></li>
<li><a href="#" style="margin-right:5px;" class="text-secondary">▶</a></li>
</ul>
</div>
<a class="btn btn-outline-info" style="float:right" href="testRegister.do">글쓰기</a>
</div>
<br>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script>
</body>
</html>

 

=========================================

 

 

9. testDetail.jsp

======================================

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board Detail</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
</head>
<body>
    <br />
    <h1 class="text-center">Board Detail</h1>
    <br />
    <br />
<div class="container">
        <form action="updateTest.do" id="viewForm" method="post"
encType="multiplart/form-data">
            <table class="table table-bordered">
<tbody>
<tr>
<th>글번호</th>
<td><input name="testId" type="text" value="${vo.testId}"
class="form-control" readonly /></td>
</tr>
<tr>
<th>제목</th>
<td><input type="text" value="${vo.testTitle}"
name="testTitle" class="form-control" /></td>
</tr>
<tr>
<th>내용</th>
<td><textarea name="testContent" class="form-control"

style="height: 200px;">${vo.testContent}</textarea></td>
</tr>
<tr>
<td colspan="2" style="text-align: right;">
<button id="btn_previous" type="button" class="btn_previous">이전</button>
                            <button id="btn_modify" type="button" class="btn_register">수정</button>
<button id="btn_delete" type="button" class="btn_delete">삭제</button>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</body>
<script type="text/javascript">
$(document).on('click', '#btn_modify', function(e) {

if (confirm("정말 수정하시겠습니까 ?") == true) {
$("#viewForm").submit();
} else {
return;
}
});
$(document).on('click', '#btn_delete', function(e) {

var testId = ${vo.testId};
if (confirm("정말 삭제하시겠습니까 ?") == true) {
$("#viewForm").attr("action", "deleteTest.do?testId="+testId);
$("#viewForm").submit();
} else {
return;
}
});
//이전 클릭 시 testList로 이동
$("#btn_previous").click(function previous() {
$(location).attr('href', 'testList.do');

});
</script>
</html>

 

======================================

 

 

10. testRegister.jsp

======================================

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board Write</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
</head>
<body>
<br/>
<h1 class="text-center">Board Write</h1>
<br/>
<br/>
<div class="container">
<form id="form_test" action="insertTest.do" method="post"
encType="multiplart/form-data">
<table class="table table-bordered">

<tbody>
<tr>
<th>제목</th>
<td><input type="text" placeholder="제목을 입력하세요."
name="testTitle" class="form-control" /></td>
</tr>
<tr>
<th>내용</th>
<td><textarea placeholder="내용을 입력하세요 ." name="testContent"
class="form-control" style="height: 200px;"></textarea></td>
</tr>
<tr>
<td colspan="2">
<button id="btn_register" type="button" class="btn_register">등록</button>
<button id="btn_previous" type="button" class="btn_previous">이전</button>
</tr>

</tbody>
</table>
</form>
</div>
</body>
<script type="text/javascript">
//글쓰기
$(document).on('click', '#btn_register', function(e) {
$("#form_test").submit();
});

//이전 클릭 시 testList로 이동
$("#btn_previous").click(function previous() {
$(location).attr('href', 'testList.do');
});
</script>
</html>

 

======================================

 

 

 

ㄴ 게시판 목록(testList.jsp)

 

 

ㄴ 글 상세보기 및 수정, 삭제 (testDetail.jsp)

 

 

 

 

 

ㄴ 글쓰기 (testRegister.jsp)

 

+ Recent posts