스트럿츠 2를 적용하여 게시판을 만들어보았습니다.
기존에 struts1 에서 만들었던 com.util.dao(db연결)와 com.util 패키지(페이징 처리)를 가져온다.
struts.i18n.encoding=UTF-8 : UTF-8로 인코딩
struts.action.extention=action : 스트럿츠에 움직이는 확장자는 기본적으로 action 이다.action이다. 나중에 Spring도 action이다.
struts.multipart.saveDir=c:\\temp : 아파치에서 파일 업로드하는 클래스에 파일업로드 하는 경로
struts.configuration.files=struts-default.xml, struts.xml : 기본 환경 세팅 파일 2개
struts.xml : 우리가 만드는 환경설정 화일
struts-default.xml : 기본적인 환경설정 화일
<?xml version="1.0" encoding="UTF-8"?>
<!-- 스트럿츠2 사용하기 위해 선언 -->
<!DOCTYPE struts
PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- struts-default : xml 파일을 불러옴 -->
<struts>
<!-- extends = struts-default 는 struts.xml 화일를 불러온다. -->
<package name="default" extends="struts-default" namespace="">
<global-results>
<result name="error">/exception/error.jsp</result>
</global-results>
</package>
<!-- include : 또 다른 환경설정을 불러옴 여기다가 새로운 화일설정을 선언해주면 된다. -->
<include file="struts-test.xml"/>
<include file="struts-board.xml"/>
</struts>
struts.xml 에서 환경설정을 등록해준다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts
PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- temp는 이 패키지의 고유 이름을 적는 곳 -->
<package name="temp" extends="default" namespace="/temp">
</package>
<!-- 패키지는 여러개 만들수있다. -->
</struts>
복사용 struts-temp.xml를 만들어놓는다.
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>Insert title here</title>
</head>
<body>
<h3>Struts2 Framework</h3>
</body>
</html>
index.jsp 웹서버 테스트
일단 기본적인 웹서버로 start 시켜본다. (톰켓 서버 자체는 이상이 없다)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions
PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2.0.dtd">
<tiles-definitions>
</tiles-definitions>
tiles.xml : 나중에 쓰기 위한 설정 파일
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>struts2</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<!-- StrutsPrepareAndExecuteFilter 2016년에 바뀜 -->
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<!-- /* 모든주소가 오면 StrutsPrepareAndExecuteFilter에서 문법검사를 한다.-->
<!-- struts2 로 환경세팅을 할것이다 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
web.xml 에서 struts2 환경 세팅을 한다.
2016년에 filterDispatcher에서 StrutsPrepareAndExecuteFilter로 바뀌었다
이제 콘솔에서 struts-default.xml 이랑 struts.xml 파일을 읽어낸다.
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>Insert title here</title>
</head>
<body>
<!-- 입력창 -->
<!-- 보내기버튼을 누르면 namespace:itwill 주소가 들어오면 struts-test.xml 로 찾아가라는 소리이다.-->
<form action="<%=cp%>/itwill/write_ok.action" method="post">
아이디 : <input type="text" name="userId"/><br/>
이름 : <input type="text" name="userName"/><br/>
<input type="submit" value="보내기"/><br/>
</form>
</body>
</html>
write.jsp의 입력창
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>Insert title here</title>
</head>
<body>
아이디 : ${userId }<br/>
이름 : ${userName }<br/>
메세지 : ${message }<br/>
</body>
</html>
view.jsp의 출력 창
package com.test;
import com.opensymphony.xwork2.ActionSupport;
// 스트럿츠2에서는 ActionSupport를 상속받는다 그러면 TestAction 이 Action 이 된다.
public class TestAction extends ActionSupport{
private static final long serialVersionUID = 1L;
private String userId;
private String userName;
private String message;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
//struts1 에 비해 struts2는 필요할때만 request,form,response 달라고 요청하면 됨 (경량컨테이너)
public String execute() throws Exception {
message = userName + "님 방가방가...";
return SUCCESS; // 작업이 잘실행되면 SUCCESS쓰라고 제시
// 반드시 대문자 안에 "success" 소문자가 들어간 상수
}
}
스트럿츠 2는 필요한 것만 가져온다.
기존 스트럿츠 1에서는 안 쓰는 response request를 매개변수로 받아왔지만
스트럿츠 2는 필요한 것만 받아온다.
나중에 스프링에서도 이방식을 사용하는데 경량 컨테이너라고 한다.
코딩 자체가 단순해진다.
spring이 스트럿츠 2의 좋은 장점을 가져가서 만들어진 것이다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts
PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- struts-test.xml 은 분배기 같은 역할이다 mvc 에서 controll 역할이다. -->
<!-- name : 이 패키지의 고유 이름 (호출해서쓰진않음 내맘대로 써주면됨) -->
<!-- 패키지는 여러개 만들수있고 name이라는 곳에 고유이름을 써주면 됨 -->
<!-- namespace : /itwill 주소로 들어오면 struts-test.xml로 들어와라 -->
<!-- 사용자 주소를 내가 여기다가 써줄수있다. -->
<!-- action name : wirte.action 생략되어있음 -->
<!-- struts2/itwill/wirte.action 으로 오게됨
result 로 진짜 주소로 이동하게됨 -->
<!-- extends 는 struts.xml에 default 맞춰줘야한다. -->
<!-- 새롭게 추가 test2 method="created" 는 String created() 로 -->
<struts>
<!-- /struts2/itwill/write.action 이 오게 되면 이패키지로 이동한다 -->
<package name="test" extends="default" namespace="/itwill">
<action name="write">
<result>/test/write.jsp</result>
</action>
<action name="write_ok" class="com.test.TestAction">
<result name="success">/test/view.jsp</result>
</action>
<action name="created">
<result>/test1/created.jsp</result>
</action>
<action name="created_ok" class="com.test1.TestAction">
<result name="ok">/test1/result.jsp</result>
</action>
</package>
<!-- class 이동: TestAction 를 거쳤다가 execute는 무조건실행되는 메소드에 실행된다음 return SUCESS를 가지고온다. -->
<package name="test2" extends="default" namespace="/modelDri">
<action name="write" class="com.test2.TestAction" method="created">
<result name="input">/test2/write.jsp</result>
<result name="success">/test2/view.jsp</result>
</action>
</package>
</struts>
struts-test.xml를 만든다.
write.jsp에서 입력을 하면 TestAction으로 이동을 하겠다는 뜻이다.
success 문자를 가지고 오면 view.jsp로 가겠다는 것
test 1
package com.test1;
public class UserDTO {
private String userId;
private String userName;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
UserDTO 생성
package com.test1;
import com.opensymphony.xwork2.ActionSupport;
// 스트럿츠2는 ActionSupport를 상속받는다.
public class TestAction extends ActionSupport {
private static final long serialVersionUID = 1L;
// dto를 가지고 와서
// dto를 한번더 감싸줘서 dto. 으로 접근하는걸 domain object라고 한다.
// 폼에서 보낼때도 dto. el태그로 받아낼때도 dto.
private UserDTO dto;
// DTO에 만들지 않은 이유는 여기서 메세지에 관련된 처리를 보여주려고,..
// 이 안에서만 만들 수 있는 변수값이 필요할때가 있기 때문에.
private String message;
// dto에 값을 넣고 싶으면 getter/setter
public UserDTO getDto() {
return dto;
}
public void setDto(UserDTO dto) {
this.dto = dto;
}
public String getMessage() {
return message;
}
public String execute() throws Exception {
// userId를 다이렉트로 접근할수가 없다
message = dto.getUserName() + "님 방가방가...";
return "ok"; // SUCESS 말고 사용자 정의 문자를 써도됨
}
}
TestAction.java
dto라는 껍데기가 써져서 dto.으로 접근해야 한다.
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>Insert title here</title>
</head>
<body>
<!-- action에 /itwill/ 적어주면 폴더가 달라도 찾아간다 -->
<form action="<%=cp%>/itwill/created_ok.action" method="post">
<!-- dto안에 getter ,setter 를 만들었으므로
dto의 껍데기가 하나 씌어져서
dto. 으로 접근해줘야 한다. -->
아이디 : <input type="text" name="dto.userId"/><br/>
이름 : <input type="text" name="dto.userName"/><br/>
<input type="submit" value="보내기"/><br/>
</form>
</body>
</html>
test 1.created.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>Insert title here</title>
</head>
<body>
<!-- dto안에 감싸져 있으므로 dto. 으로 접근해줘야 한다. -->
아이디:${dto.userId }<br/>
이름:${dto.userName }<br/>
매세지:${message }<br/>
</body>
</html>
test 1.result.jsp
받아낼 때도 dto로 한 번 더 써줘야 한다.
extends 확장이라는 의미로 패키지를 사용할 수 있게 된다.
com.test2
package com.test2;
public class UserDTO {
private String userId;
private String userPwd;
private String userName;
private String mode; // mode 하나가 필요하다
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
}
com.test2.UserDTO
package com.test2;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
public class TestAction extends ActionSupport
implements Preparable, ModelDriven<UserDTO> {
// 스트럿츠는 이구조를 반드시 써줘야 한다.
// dto 안에있는 내용은 userId,pwd,name 를 struts2가 알아서 넘겨준다.
// 바로 modelDriven<UserDTO> 한테 UserDTO를 맡긴것이다.(니가 알아서 DTO를 관리를 해!)
// dto가 객체이기떄문에 객체생성을 prepare메소드를 통해 객체를 생성함
// getModel() 를 통해 dto를 modelDriven이 가지고 간다.
private static final long serialVersionUID = 1L;
private UserDTO dto;
// dto는 getter만 만든다.
// getDTO()는
// struts1 에서 쓰인 보드액션에서
// request.setAttribute("dto",dto)를 안써줘도
// 자동으로 보내게 된다.
public UserDTO getDto() {
return dto;
}
@Override
public void prepare() throws Exception {
dto = new UserDTO();
}
@Override
public UserDTO getModel() {
return dto;
}
// 이제부터 내가 원하는 메소드 이름으로 쓰면 된다.
public String created() throws Exception {
// 모드 체크
// dto의 널값과 equals로 널을 두번 비교해준다
// equals가 앞에 오면 안됨
if(dto==null||dto.getMode()==null||dto.getMode().equals("")) {
return INPUT; // 아까 SUCESS와 비슷 내장된 반환값 소문자 input이 들어가있음
}
// dto가 널이아닐때
// request를 이렇게 만들면 됨
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("message", "스트럿츠 2...");
// request.setAttribute("dto", dto); dto도 원래 이렇게 넘겨야되는데
//위에 getDTO()떄문에 자동으로 넘김
return SUCCESS; // 사용자가 값을 입력할때
}
}
com.test2.TestAction.java
자동으로 dto를 넘겨준다.
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>Insert title here</title>
</head>
<body>
<!-- 입력창 열때도 write.action 보낼때도 write.action -->
<form action="<%=cp%>/modelDri/write.action" method="post">
아이디 : <input type="text" name="userId"/><br/>
패스워드 : <input type="password" name="userPwd"/><br/>
이름 : <input type="text" name="userName"/><br/>
<input type="hidden" name="mode" value="save"/>
<input type="submit" value="보내기"/><br/>
</form>
</body>
</html>
write.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>Insert title here</title>
</head>
<body>
아이디 : ${dto.userId }<br/>
패스워드 : ${dto.userPwd}<br/>
이름 : ${dto.userName}<br/>
메세지 : ${message }<br/> <!-- dto에 없는 내용을 보낼때 -->
</body>
</html>
view.jsp
패키지 name = test2 extends="default" namespace = "/modelDri"를 추가해준다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts
PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- struts-test.xml 은 분배기 같은 역할이다 mvc 에서 controll 역할이다. -->
<!-- name : 이 패키지의 고유 이름 (호출해서쓰진않음 내맘대로 써주면됨) -->
<!-- 패키지는 여러개 만들수있고 name이라는 곳에 고유이름을 써주면 됨 -->
<!-- namespace : /itwill 주소로 들어오면 struts-test.xml로 들어와라 -->
<!-- 사용자 주소를 내가 여기다가 써줄수있다. -->
<!-- action name : wirte.action 생략되어있음 -->
<!-- struts2/itwill/wirte.action 으로 오게됨
result 로 진짜 주소로 이동하게됨 -->
<!-- class 이동: TestAction 를 거쳤다가 execute는 무조건실행되는 메소드에 실행된다음 return SUCESS를 가지고온다. -->
<!-- extends 는 struts.xml에 default 맞춰줘야한다. -->
<!-- 새롭게 추가 test2 method="created" 는 String created() 로 -->
<struts>
<package name="test" extends="default" namespace="/itwill">
<action name="write">
<result>/test/write.jsp</result>
</action>
<action name="write_ok" class="com.test.TestAction">
<result name="success">/test/view.jsp</result>
</action>
<action name="created">
<result>/test1/created.jsp</result>
</action>
<action name="created_ok" class="com.test1.TestAction">
<result name="ok">/test1/result.jsp</result>
</action>
</package>
<!-------------------------------패키지를 하나더 추가해준다. ----------------------------->
<!-- /modelDri/write 를 치면 TestAction 으로 가서 created메소드를 찾아서 결과값에 따라 jsp로 이동 -->
<package name="test2" extends="default" namespace="/modelDri">
<action name="write" class="com.test2.TestAction" method="created">
<result name="input">/test2/write.jsp</result>
<result name="success">/test2/view.jsp</result>
</action>
</package>
</struts>
struts-test.xml
prepare() 객체를 생성해주고
getModel()를 가지고 ModelDriven <UserDTO>로 가지고 들어가고
getDto()를 통해서 넘겨준다.
package com.board;
public class BoardDTO {
private int listNum; // 일련번호 db에있는것이 아니므로 띄어서 만듬
private int boardNum;
private String name;
private String pwd;
private String email;
private String subject;
private String content;
private String ipAddr;
private int groupNum;
private int depth;
private int orderNo;
private int parent;
private int hitCount;
private String created;
// dto에 있으면 자동으로 스트럿츠가 자동으로 넘겨준다.
private String searchKey;
private String searchValue;
private String pageNum;
private String mode; // 입력 수정 댓글
public int getListNum() {
return listNum;
}
public void setListNum(int listNum) {
this.listNum = listNum;
}
public int getBoardNum() {
return boardNum;
}
public void setBoardNum(int boardNum) {
this.boardNum = boardNum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public int getGroupNum() {
return groupNum;
}
public void setGroupNum(int groupNum) {
this.groupNum = groupNum;
}
public int getDepth() {
return depth;
}
public void setDepth(int depth) {
this.depth = depth;
}
public int getOrderNo() {
return orderNo;
}
public void setOrderNo(int orderNo) {
this.orderNo = orderNo;
}
public int getParent() {
return parent;
}
public void setParent(int parent) {
this.parent = parent;
}
public int getHitCount() {
return hitCount;
}
public void setHitCount(int hitCount) {
this.hitCount = hitCount;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getSearchKey() {
return searchKey;
}
public void setSearchKey(String searchKey) {
this.searchKey = searchKey;
}
public String getSearchValue() {
return searchValue;
}
public void setSearchValue(String searchValue) {
this.searchValue = searchValue;
}
public String getPageNum() {
return pageNum;
}
public void setPageNum(String pageNum) {
this.pageNum = pageNum;
}
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
}
BoardDTO
package com.board;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.util.MyUtil;
import com.util.dao.CommonDAO;
import com.util.dao.CommonDAOImpl;
public class BoardAction extends ActionSupport
implements Preparable, ModelDriven<BoardDTO>{
private static final long serialVersionUID = 1L;
private BoardDTO dto;
// getDto 가 modelDriven에 의해서 원하는곳으로 넘어간다.
public BoardDTO getDto() {
return dto;
}
@Override
public BoardDTO getModel() {
return dto;
}
@Override
public void prepare() throws Exception {
// modelDriven이 객체를 넘기려면 객체를 생성해야한다.
dto = new BoardDTO();
}
// 사용자가 created메소드로 찾아오면
// 입력할때 쓸것인가
// 겉모습만 보여줄것인가
public String created() throws IOException {
HttpServletRequest request = ServletActionContext.getRequest();
// 앞뒤가 바뀌면 안된다. equals가 뒤에 와야된다.
// 게시물 입력창을 띄운다.
if(dto==null||dto.getMode()==null||dto.getMode().equals("")) {
request.setAttribute("mode", "create");
return INPUT;
}
// dto가 null이 아니면 입력이 된것이다.
// 입력 코딩은 좀있다가
CommonDAO dao = CommonDAOImpl.getInstance();
int maxBoardNum = dao.getIntValue("bbs.maxBoardNum");
// 처음들어가는 데이터
dto.setBoardNum(maxBoardNum + 1);
dto.setIpAddr(request.getRemoteAddr());
dto.setGroupNum(dto.getBoardNum());
dto.setDepth(0);
dto.setOrderNo(0);
dto.setParent(0);
dao.insertData("bbs.insertData", dto);
return SUCCESS;
}
// 리스트 띄우기
public String list() throws IOException {
CommonDAO dao = CommonDAOImpl.getInstance();
MyUtil myUtil = new MyUtil();
// request 사용하기 위해 생성
HttpServletRequest request = ServletActionContext.getRequest();
String cp = request.getContextPath();
int numPerPage = 5;
int totalPage = 0;
int totalDataCount = 0;
int currentPage = 1;
if(dto.getPageNum()!=null && !dto.getPageNum().equals("")) {
currentPage = Integer.parseInt(dto.getPageNum());
}
if(dto.getSearchValue()==null||dto.getSearchValue().equals("")) {
dto.setSearchKey("subject");
dto.setSearchValue("");
}
if(request.getMethod().equalsIgnoreCase("GET")) {
dto.setSearchValue(URLDecoder.decode(dto.getSearchValue(),"UTF-8"));
}
// 전체페이지 MAP 필요
Map<String, Object> hMap = new HashMap<String,Object>();
hMap.put("searchKey", dto.getSearchKey());
hMap.put("searchValue", dto.getSearchValue());
// 전체 데이터 개수 구하기
totalDataCount = dao.getIntValue("bbs.dataCount",hMap);
if(totalDataCount!=0) {
totalPage = myUtil.getPageCount(numPerPage, totalDataCount);
}
// 삭제가 있을때 문제가 생길때
if(currentPage > totalPage) {
currentPage = totalPage;
}
int start = (currentPage-1)*numPerPage+1;
int end = currentPage*numPerPage;
hMap.put("start", start);
hMap.put("end", end);
// hamp에는 4개가 들어가있다 키와벨류start,end
List<Object> lists = (List<Object>)dao.getListData("bbs.listData",hMap);
// 일련번호를 만들기
int listNum,n=0;
Iterator<Object> it = lists.iterator();
while(it.hasNext()) {
// dto를 하나꺼내서 만들어서 vo에 listNum에 넣어준다.
BoardDTO vo = (BoardDTO)it.next();
listNum = totalDataCount-(start+n-1);
vo.setListNum(listNum); // 삭제가 되도 일련번호가 만들어짐
n++;
}
String param = "";
String urlList = "";
String urlArticle = "";
// 널이 아니면 검색을 했다.
if(!dto.getSearchValue().equals("")) {
param = "searchKey=" + dto.getSearchKey();
param += "&searchValue="
+ URLEncoder.encode(dto.getSearchValue(),"UTF-8");
}
urlList = cp + "/bbs/list.action";
urlArticle = cp + "/bbs/article.action?pageNum="+currentPage;
// param 널이 아니면 검색이 됐다.
if(!param.equals("")) {
urlList += "?" + param;
urlArticle += "&" + param;
}
// 데이터 넘김
// 이 내개 데이터와 success를 가지고 돌아감
request.setAttribute("lists", lists);
request.setAttribute("totalDataCount", totalDataCount);
request.setAttribute("pageIndexList",
myUtil.pageIndexList(currentPage, totalPage, urlList));
request.setAttribute("urlArticle", urlArticle);
return SUCCESS;
}
// 클릭해서 dto는 자동으로 넘어온다.
public String article() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
CommonDAO dao = CommonDAOImpl.getInstance();
// 스트럿츠2가 자동으로 dto를 넘겨줘서 pageNum과 boardNum이 나오게 된다.
/*System.out.print(dto.getSearchKey());
System.out.print(dto.getSearchValue());
System.out.print(dto.getPageNum());
System.out.print(dto.getBoardNum());*/
// dao에서 하나의 데이터를 가져올것이다.
// 넘어오는값을 변수에 빼놓는다.
String searchKey = dto.getSearchKey();
String searchValue = dto.getSearchValue();
String pageNum = dto.getPageNum();
int boardNum = dto.getBoardNum();
if(searchValue==null||searchValue.equals("")) {
searchKey = "subject";
searchValue = "";
}
if(request.getMethod().equalsIgnoreCase("GET")) {
searchValue = URLDecoder.decode(searchValue, "UTF-8");
}
// 조회수 증가
dao.updateData("bbs.hitCountUpdate", boardNum);
// 하나의 데이터를 읽어와서 dto에 넣어준다.
dto = (BoardDTO)dao.getReadData("bbs.readData",boardNum);
// nullnullnull3 검색을 했는데도 key,value,pagenum 없어짐..
// 위에는 있어서 출력이 됐는데
// 진행하다 보니까 자동으로 넘어온 dto가 이 밑에서
// getReadData에 의해서 기존에 있는게 덮어져서 초기화됨
// 맨 마지막에 boardNum만 보이게 된다.
// 우리가 별도로 자동으로 넘어온 dto를 빼놔서
// 아래에서 사용을 하게되는것이다.
/*System.out.print(dto.getSearchKey());
System.out.print(dto.getSearchValue());
System.out.print(dto.getPageNum());
System.out.print(dto.getBoardNum());*/
if(dto==null) {
return "read-error";
}
// dto에서 꺼냈으니 content는 있으나 키벨류페이지넘은 초기화되어있음..
int lineSu = dto.getContent().split("\r\n").length;
dto.setContent(dto.getContent().replaceAll("\r\n", "<br/>"));
// 이전글 다음글보낼것임
Map<String, Object> hMap = new HashMap<>();
// hMap.put("searchKey", dto.getSearchKey()); 이렇게 넣어주면안됨 위에 자동으로 넣은 dto sk,sv,pn 이 초기화 되어있어서
// 널이 들어가면 검색이 안된다..
hMap.put("searchKey", searchKey); // 그럼 여기다가 위에서 dto.getSearchKey 로
// 받은 searchKey변수 를 써줘야 한다.
hMap.put("searchValue", searchValue);
hMap.put("groupNum", dto.getGroupNum());
hMap.put("orderNo", dto.getOrderNo());
// 이전글
BoardDTO preDTO = (BoardDTO)dao.getReadData("bbs.preReadData",hMap);
int preBoardNum = 0;
String preSubject = "";
if(preDTO!=null) {
preBoardNum = preDTO.getBoardNum();
preSubject = preDTO.getSubject();
}
BoardDTO nextDTO = (BoardDTO)dao.getReadData("bbs.nextReadData",hMap);
int nextBoardNum = 0;
String nextSubject = "";
if(nextDTO!=null) {
nextBoardNum = nextDTO.getBoardNum();
nextSubject = nextDTO.getSubject();
}
// 넘어가는 주소
String params = "pageNum=" + pageNum;
if(!searchValue.equals("")) {
params += "&searchKey=" + searchKey;
params += "&searchValue="
+ URLEncoder.encode(searchValue,"UTF-8");
}
request.setAttribute("preBoardNum", preBoardNum);
request.setAttribute("preSubject",preSubject);
request.setAttribute("nextBoardNum", nextBoardNum);
request.setAttribute("nextSubject",nextSubject);
request.setAttribute("params",params);
request.setAttribute("lineSu",lineSu);
request.setAttribute("pageNum",pageNum);
// 이제 sql에 이전글 다음글로 넘어가게 된다.
return SUCCESS;
}
}
BoardAction.java
getReadData를 하면서 dto가 초기화됨
초기화되기 전에 dto의 값들을 미리 꺼내서 변수에 담아둔다. (중요)
마지막에 hMap에 빼는 데이터를 넣어주면 된다.
<%@ page contentType="text/html; charset=UTF-8"%>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>게 시 판</title>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/style.css"/>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/created.css"/>
<script type="text/javascript" src="<%=cp%>/board/js/util.js"></script>
<script type="text/javascript">
function sendIt(){
var f = document.myForm;
str = f.subject.value;
str = str.trim();
if(!str){
alert("\n제목을 입력하세요.");
f.subject.focus();
return;
}
f.subject.value = str;
str = f.name.value;
str = str.trim();
if(!str){
alert("\n이름을 입력하세요.");
f.name.focus();
return;
}
/* if(!isValidKorean(str)){
alert("\n이름을 정확히 입력하세요.");
f.name.focus()
return;
} */
f.name.value = str;
if(f.email.value){
if(!isValidEmail(f.email.value)){
alert("\n정상적인 E-Mail을 입력하세요.");
f.email.focus();
return;
}
}
str = f.content.value;
str = str.trim();
if(!str){
alert("\n내용을 입력하세요.");
f.content.focus();
return;
}
f.content.value = str;
str = f.pwd.value;
str = str.trim();
if(!str){
alert("\n패스워드를 입력하세요.");
f.pwd.focus();
return;
}
f.pwd.value = str;
/* 입력 수정 댓글 */
/* request.setAttribute("mode", "create"); */
/* 주소를 분리해놨다. */
if(f.mode.value=="create") {
f.action = "<%=cp%>/bbs/created.action";
}else if(f.mode.value=="update") {
f.action = "<%=cp%>/bbs/updated.action";
}else if(f.mode.value=="reply") {
f.action = "<%=cp%>/bbs/reply.action";
}
f.submit();
}
</script>
</head>
<body>
<div id="bbs">
<div id="bbs_title">
게 시 판 (Struts2)
</div>
<form action="" method="post" name="myForm">
<div id="bbsCreated">
<div class="bbsCreated_bottomLine">
<dl>
<dt>제 목</dt>
<dd>
<input type="text" name="subject" value="${dto.subject }" size="60"
maxlength="100" class="boxTF"/>
</dd>
</dl>
</div>
<div class="bbsCreated_bottomLine">
<dl>
<dt>작성자</dt>
<dd>
<input type="text" name="name" value="${dto.name }" size="35"
maxlength="20" class="boxTF"/>
</dd>
</dl>
</div>
<div class="bbsCreated_bottomLine">
<dl>
<dt>E-Mail</dt>
<dd>
<input type="text" name="email" value="${dto.email }" size="35"
maxlength="50" class="boxTF"/>
</dd>
</dl>
</div>
<div id="bbsCreated_content">
<dl>
<dt>내 용</dt>
<dd>
<textarea rows="12" cols="63" name="content"
class="boxTA">${dto.content }</textarea>
</dd>
</dl>
</div>
<div class="bbsCreated_noLine">
<dl>
<dt>패스워드</dt>
<dd>
<input type="password" name="pwd" value="${dto.pwd }" size="35"
maxlength="7" class="boxTF"/>
(게시물 수정 및 삭제시 필요!!)
</dd>
</dl>
</div>
</div>
<div id="bbsCreated_footer">
<!-- 수정으로 쓸곳 , 수정하기 위해서 필요한것이다. -->
<input type="hidden" name="boardNum" value="${dto.boardNum }"/>
<input type="hidden" name="pageNum" value="${dto.pageNum }"/>
<!-- 댓글달때 필요하므로 써놓음 -->
<input type="hidden" name="groupNum" value="${dto.groupNum }"/>
<input type="hidden" name="orderNo" value="${dto.orderNo }"/>
<input type="hidden" name="depth" value="${dto.depth }"/>
<input type="hidden" name="parent" value="${dto.parent }"/>
<!-- 입력용인지 수정용인지 댓글용인지 -->
<!-- BoardAction에서 입력창은
request.setAttribute("mode","create") 로 담겨서 넘어오므로 -->
<input type="hidden" name="mode" value="${mode }"/>
<input type="button" value=" 등록하기 " class="btn2" onclick="sendIt();"/>
<input type="reset" value=" 다시입력 " class="btn2"
onclick="document.myForm.subject.focus();"/>
<input type="button" value=" 작성취소 " class="btn2"
onclick="javascript:location.href='<%=cp%>/bbs/list.action';"/>
</div>
</form>
</div>
</body>
</html>
created.jsp
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts
PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- struts-default : xml 파일을 불러옴 -->
<!-- include : 또 다른 환경설정을 불러옴 -->
<struts>
<package name="default" extends="struts-default" namespace="">
<global-results>
<result name="error">/exception/error.jsp</result>
</global-results>
</package>
<include file="struts-test.xml"/>
<include file="struts-board.xml"/>
</struts>
struts.xml 에 include file로 등록해준다.
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>게 시 판</title>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/style.css"/>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/list.css"/>
<script type="text/javascript">
function searchData() {
var f = document.searchForm;
f.action = "<%=cp%>/bbs/list.action";
f.submit();
}
</script>
</head>
<body>
<div id="bbsList">
<div id="bbsList_title">
게 시 판(Struts2)
</div>
<div id="bbsList_header">
<div id="leftHeader">
<form action="" method="post" name="searchForm">
<select name="searchKey" class="selectField">
<option value="subject">제목</option>
<option value="name">작성자</option>
<option value="content">내용</option>
</select>
<input type="text" name="searchValue" class="textField"/>
<!-- 검색 -->
<input type="button" value=" 검 색 " class="btn2" onclick="searchData();"/>
</form>
</div>
<div id="rightHeader">
<input type="button" value=" 글올리기 " class="btn2"
onclick="javascript:location.href='<%=cp%>/bbs/created.action';"/>
</div>
</div>
<div id="bbsList_list">
<div id="title">
<dl>
<dt class="num">번호</dt>
<dt class="subject">제목</dt>
<dt class="name">작성자</dt>
<dt class="created">작성일</dt>
<dt class="hitCount">조회수</dt>
</dl>
</div>
<div id="lists">
<c:forEach var="dto" items="${lists }">
<dl>
<dd class="num">${dto.listNum }</dd>
<dd class="subject">
<a href="${urlArticle }&boardNum=${dto.boardNum }">
${dto.subject }</a>
</dd>
<dd class="name">${dto.name }</dd>
<dd class="created">${dto.created }</dd>
<dd class="hitCount">${dto.hitCount }</dd>
</dl>
</c:forEach>
</div>
<div id="footer">
<p>
<c:if test="${totalDataCount!=0 }">
${pageIndexList }
</c:if>
<c:if test="${totalDataCount==0 }">
등록된 게시물이 없습니다.
</c:if>
</div>
</div>
</div>
</body>
</html>
list.jsp
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts
PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- Controller 역할 -->
<!-- extends 의 default 는 packagename 의 default struts.xml과 연결되게끔함 -->
<!-- 주소창을 여기서 친다 -->
<struts>
<package name="board" extends="default" namespace="/bbs">
<!-- /bbs에 created.Action 이 오면 BoardAction 으로 가서 created메소드를 실행해라 -->
<action name="created" class="com.board.BoardAction" method="created">
<result name="input">/board/created.jsp</result>
<!-- 입력이 됬으므로 리다이랙트(수정,세션된건) -->
<result name="success" type="redirectAction">list</result>
</action>
<action name="list" class="com.board.BoardAction" method="list">
<result name="success">/board/list.jsp</result>
</action>
<action name="article" class="com.board.BoardAction" method="article">
<result name="success">/board/article.jsp</result>
</action>
</package>
</struts>
struts-board.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="bbs">
<!-- 별칭을줘서 간단하게 쓸수있다. -->
<typeAlias alias="boardDTO" type="com.board.BoardDTO"/>
<select id="maxBoardNum" resultClass="int">
select nvl(max(boardNum),0) from bbs
</select>
<insert id="insertData" parameterClass="boardDTO">
insert into bbs (boardNum,name,pwd,email,subject,content,
ipAddr,groupNum,depth,orderNo,parent,hitCount,created) values
(#boardNum#,#name#,#pwd#,#email#,#subject#,#content#,
#ipAddr#,#groupNum#,#depth#,#orderNo#,#parent#,0,sysdate)
</insert>
<select id="dataCount" resultClass="int" parameterClass="map">
select nvl(count(*),0) from bbs
where $searchKey$ like '%' || #searchValue# || '%'
</select>
<!-- boardDTO 위에서 별칭으로 만든걸 반환할수있다. -->
<!-- 그룹은 큰순서로 정렬 , orderNo 작은순서로 정렬 -->
<select id="listData" resultClass="boardDTO" parameterClass="map">
select * from (
select rownum rnum, data.* from (
select boardNum,name,subject,depth,hitCount,
to_char(created,'YYYY-MM-DD') created from bbs
where $searchKey$ like '%' || #searchValue# || '%'
order by groupNum desc,orderNo asc) data)
<![CDATA[
where rnum>=#start# and rnum<=#end#
]]>
</select>
<!-- Article -->
<!-- 조회수 증가 -->
<update id="hitCountUpdate" parameterClass="int">
update bbs set hitCount=hitCount+1 where boardNum=#boardNum#
</update>
<!-- 하나의 데이터 가져옴 -->
<select id="readData" parameterClass="int" resultClass="boardDTO">
select boardNum,name,pwd,email,subject,content,ipAddr,
groupNum,depth,orderNo,parent,hitCount,created
from bbs where boardNum=#boardNum#
</select>
<!-- 이전글 다음글 -->
<!-- 그룹넘버가 같으면서 orderNo가 현재보다 작아야한다. -->
<!-- 이전글이 최신글이다. -->
<select id="preReadData" parameterClass="map" resultClass="boardDTO">
select data.* from (
select boardNum,subject from bbs
where ($searchKey$ like '%' || #searchValue# || '%')
<![CDATA[
and ((groupNum=#groupNum# and orderNo<#orderNo#)
or(groupNum>#groupNum#))
order by groupNum asc,orderNo desc) data
where rownum=1
]]>
</select>
<!-- 다음글이 예전에 쓴글 -->
<select id="nextReadData" parameterClass="map" resultClass="boardDTO">
select data.* from (
select boardNum,subject from bbs
where ($searchKey$ like '%' || #searchValue# || '%')
<![CDATA[
and ((groupNum=#groupNum# and orderNo>#orderNo#)
or(groupNum<#groupNum#))
order by groupNum desc,orderNo asc) data
where rownum=1
]]>
</select>
</sqlMap>
board_sqlMap.xml dao 작업을 하기 위한 쿼리문
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!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>게 시 판</title>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/style.css"/>
<link rel="stylesheet" type="text/css" href="<%=cp%>/board/css/article.css"/>
</head>
<body>
<div id="bbs">
<div id="bbs_title">
게 시 판 (Struts2)
</div>
<div id="bbsArticle">
<div id="bbsArticle_header">
${dto.subject }
</div>
<div class="bbsArticle_bottomLine">
<dl>
<dt>작성자</dt>
<dd>${dto.name }</dd>
<dt>줄수</dt>
<dd>${lineSu }</dd>
</dl>
</div>
<div class="bbsArticle_bottomLine">
<dl>
<dt>등록일</dt>
<dd>${dto.created }</dd>
<dt>조회수</dt>
<dd>${dto.hitCount }</dd>
</dl>
</div>
<div id="bbsArticle_content">
<table width="600" border="0">
<tr>
<td style="padding-left: 20px 80px 20px 62px;"
valign="top" height="200">
${dto.content }
</td>
</tr>
</table>
</div>
<div class="bbsArticle_bottomLine">
이전글:
<!-- 제목이 있을때만 보여준다. -->
<c:if test="${!empty preSubject }">
<a href="<%=cp %>/bbs/article.action?${params }&boardNum=${preBoardNum }">
${preSubject }</a>
</c:if>
</div>
<div class="bbsArticle_noLine">
다음글:
<!-- 제목이 있을때만 보여준다. -->
<c:if test="${!empty nextSubject }">
<a href="<%=cp%>/bbs/article.action?${params}&boardNum=${nextBoardNum}">
${nextSubject }</a>
</c:if>
</div>
</div>
<div class="bbsArticle_noLine" style="text-align: right">
From : ${dto.ipAddr }
</div>
<div id="bbsArticle_footer">
<div id="leftFooter">
<input type="button" value=" 수정 " class="btn2" onclick=""/>
<input type="button" value=" 삭제 " class="btn2" onclick=""/>
</div>
<div id="rightFooter">
<input type="button" value=" 리스트 " class="btn2"
onclick="javascript:location.href='<%=cp%>/bbs/list.action?${params }'"/>
</div>
</div>
</div>
</body>
</html>
게시물을 클릭했을 때 article.jsp 페이지
다음 시간에는 스트럿츠 2 + 아이 바티스를 이용한 수정 삭제 답변를 해서 올릴 것이다.
'BACKEND > 아파치 스트럿츠 1 , 2' 카테고리의 다른 글
[struts2] 스트럿츠2 + iBatis를 이용한 답변형 게시판 중 (2) (답변형 게시판 , 수정 , 삭제 ) (0) | 2022.03.14 |
---|---|
[Struts2] 스트럿츠2 + iBatis 파일업로드/다운로드/보기 기능 (0) | 2022.03.14 |
[Struts1] 스트럿츠1 + iBatis 파일업로드 (2) | 2022.03.14 |
[struts1] 스트럿츠1 + iBatis 게시판 만들기 (0) | 2022.03.07 |