우리가 getAttribute & setAttribute를 해서 반복되는 코드를 HashMapBinder로 공통코드로 만들었음.
HashMapBinder로 Post방식으로 나머지 req로 값들을 받아오기 위해서 (사진) 추가했다.
[원래코드]
public class HashMapBinder {
Logger logger = LoggerFactory.getLogger(HashMapBinder.class);
HttpServletRequest req = null;
HashMapBinder(HttpServletRequest req)
{
this.req = req;
}
public void bind(Map<String,Object> pMap)
{
pMap.clear(); // map을 비워주는 역할
// <input type ="text" name = "n_title"/>
// <input type ="text" name = "n_content"/>
// <input type ="text" name = "n_writer"/>
Enumeration<String> em = req.getParameterNames();
String key = em.nextElement();
pMap.put(key,req.getParameter(key));
}
}
}
이미지 처리 시 HashMapBinder로 Post방식으로 나머지 req로 값들을 받아오기 위해서 (사진) 추가했다.
[수정후]
public class HashMapBinder {
Logger logger = Logger.getLogger(HashMapBinder.class);
HttpServletRequest req = null;
MultipartRequest multi = null;
String realFolder = "C:\\Program Files\\workspace_jsp\\nae2Gym\\src\\main\\webapp\\pds";
String encType = "utf-8";
int maxSize = 5*1024*1024;
//우리가 getAttribute & setAttribute를 해서 반복되는 코드를 HashMapBinder로 공통코드로 만들었음.
//왜 req인가? -> 생각해볼 필요가 있다.
// public void multiBinder(Map<String,Object> pMap) 파라미터에있는 주소번지는 어디서 결정되나요?
// boardController 에서 주입 받는다.(이 공통코드를 클래스를 주입받는다.
public void multiBinder(Map<String,Object> pMap)
{
pMap.clear();//기존의 들어있는 정보는 비운다.
try {
multi = new MultipartRequest(req, realFolder, maxSize, encType, new DefaultFileRenamePolicy());
}
catch(Exception e) {
logger.info(e.toString());
}
//이미지 처리말고 Post에서 첨부파일에 있는 포스트 방식일 때 사용하는 메소드
//첨부파일이 아닌 다른 정보에 대해서 받아준다.
Enumeration<String> em = req.getParameterNames();
while(em.hasMoreElements()) {
//키값 꺼내기
String key = em.nextElement();//n_title, n_content, n_writer
pMap.put(key, req.getParameter(key));
}////////////// end of while
// 첨부파일에 대한 처리를 말함.
Enumeration<String> files = multi.getFileNames();
String fullPah = null;//파일 정보에 대한 전체경로
String filename = null;//파일이름
//첨부파일이 있다면?
if(files !=null) {
//파일 이름을 클래스로 정의하는 객체 - 파일객체가 생성되었다고 해서 그 안에 내용까지 포함하진 않음
//파일 크기를 계산해주는 메소드 지원함
File file = null;
while(files.hasMoreElements()) {
String fname = files.nextElement();
filename = multi.getFilesystemName(fname);
pMap.put("bs_file", filename);//avartar.png
//File객체 생성하기
file = new File(realFolder+"\\"+filename);
}
//첨부파일의 크기를 담기
double size = 0;
if(file !=null) {
size = file.length();
size = size/(1024);
pMap.put("bs_size", size);
}
}
}
public HashMapBinder(HttpServletRequest req) {
this.req = req;
}
public void bind(Map<String,Object> pMap) {
pMap.clear();
//<input type="text" name="n_title">
//<input type="text" name="n_content">
//<input type="text" name="n_writer">
Enumeration<String> em = req.getParameterNames();
while(em.hasMoreElements()) {
//키값 꺼내기
String key = em.nextElement();//n_title, n_content, n_writer
pMap.put(key, req.getParameter(key));
}////////////// end of while
}
[원래코드]
if("noticeList".equals(upmu[1])) {//select
logger.info("noticeList");
List<Map<String ,Object>> nList = null;//nList.size()가 n개
// NoticeLogic의 메소드 호출 - 객체주입 - 내가(책임) 아님 스프링(제어역전)
hmb.bind(pMap);
nList = nLogic.noticeList(pMap);
//원본에다가 담아 두자
req.setAttribute("nList", nList);
path.append("noticeList.jsp");
isRedirect = false;//false이면 forward처리됨
}
else if("noticeDetail".equals(upmu[1])) {//select
logger.info("noticeDetail");
List<Map<String ,Object>> nList = null;//nList.size()=1
// NoticeLogic의 메소드 호출 - 객체주입 - 내가(책임) 아님 스프링(제어역전)
//select * from notice where n_no=5;
hmb.bind(pMap);
nList = nLogic.noticeList(pMap);
//원본에다가 담아 두자
req.setAttribute("nList", nList);
path.append("noticeDetail.jsp");
isRedirect = false;//false이면 forward처리됨
}
[수정코드]
if("boardList".equals(upmu[1])) {//select - 1-3버전에서는 이 장면을 메소드 단위로 변경하고 싶다(req, res)넘겨 받을 수 있어야 한다. -문제 해결못하니까
logger.info("boardList");
List<Map<String ,Object>> bList = null;//nList.size()가 n개
// NoticeLogic의 메소드 호출 - 객체주입 - 내가(책임) 아님 스프링(제어역전)
hmb.bind(pMap);
bList = bLogic.boardList(pMap);
//원본에다가 담아 두자
req.setAttribute("bList", bList);
//pageMove[0]=forward, pageMove[1]=/board/boardList.jsp
path = "forward:board/boardList";
}//end of 목록조회
//상세조회일때 - select - 1건 - Map or VO괜찮아 - read.jsp
else if("boardDetail".equals(upmu[1])) {
logger.info("boardDetail");
List<Map<String ,Object>> bList = null;//nList.size()=1
// NoticeLogic의 메소드 호출 - 객체주입 - 내가(책임) 아님 스프링(제어역전)
//select * from notice where n_no=5;
hmb.bind(pMap);
bList = bLogic.boardList(pMap);
//원본에다가 담아 두자
req.setAttribute("bList", bList);
path="forward:board/boardDetail";
}
path.append("noticeDetail.jsp");
isRedirect = false;
이 부분들이 하나로 통일됐음상세보기와 전체보기는 나누어야 하나? 아니면 하나의 메소드로 설계해야될까?
if문 for문으로 경우의 수를 구분하는 건 직관적이지 않다.
응답 페이지가 다르잖아
1건일 떈 :
/board/read.jsp
webapp{1건+컨트롤러분리했다.} /board/boardDetail.gd2 로 호출함.
Test Case : b_no로 호출한다. --> Pk이다 --> Get방식이다.
else if("boardDetail".equals(upmu[1]))
{
logger.info("BoardController클래스 안 : if ==>boardDetail");
List<Map<String ,Object>> bList = null;//nList.size()=1
// NoticeLogic의 메소드 호출 - 객체주입 - 내가(책임) 아님 스프링(제어역전)
//select * from notice where n_no=5;
hmb.bind(pMap);
bList = bLogic.boardList(pMap);
//원본에다가 담아 두자
req.setAttribute("bList", bList);
path = "forward:/board/boardDetail.jsp";
}
한건인데 왜 List에 담았음? --> jsp에 출력하기 위해서
[원래코드]
else if("noticeInsert".equals(upmu[1])) {//insert
logger.info("noticeInsert");
int result = 0;
hmb.bind(pMap);
result = nLogic.noticeInsert(pMap);
if(result == 1) {
path.append("noticeList.gd");
isRedirect = true;//sendRedirect
}else {
path.append("noticeError.jsp");
isRedirect = true;
}
}else if("noticeUpdate".equals(upmu[1])) {//update
logger.info("noticeUpdate");
int result = 0;
hmb.bind(pMap);
result = nLogic.noticeUpdate(pMap);
if(result == 1) {
path.append("noticeList.gd");
isRedirect = true;
}else {
path.append("noticeError.jsp");
isRedirect = true;
}
[수정코드]
else if("boardInsert".equals(upmu[1])) {//insert
logger.info("boardInsert");
int result = 0;
hmb.bind(pMap);
result = bLogic.boardInsert(pMap);
if(result == 1) {//글등록 성공했을때
path="redirect:board/boardList";//jsp --(redirect)---->boardInsert.gd2 -----(redirect)------> boardList.gd2 --(forward)---> jsp
}else {
path="redirect:/board/boardError.jsp";
}
}////////////end of boardInsert
//수정일때 - get,put방식 - 큰의미 없다 - Restful 상징성을 표현함 - update:1(수정성공) or 0(수정안됨)
else if("boardUpdate".equals(upmu[1])) {//update
logger.info("boardUpdate");
int result = 0;
hmb.bind(pMap);
result = bLogic.boardUpdate(pMap);
if(result == 1) {//글등록 성공했을때
path="redirect:board/boardList";
}else {
path="redirect:/board/boardError.jsp";
}
}///////////end of boardUpdate
BoardController
if("boardList".equals(upmu[1])) {//select - 1-3버전에서는 이 장면을 메소드 단위로 변경하고 싶다(req, res)넘겨 받을 수 있어야 한다. -문제 해결못하니까
logger.info("boardList");
List<Map<String ,Object>> bList = null;//nList.size()가 n개
// NoticeLogic의 메소드 호출 - 객체주입 - 내가(책임) 아님 스프링(제어역전)
hmb.bind(pMap);
bList = bLogic.boardList(pMap);
//원본에다가 담아 두자
req.setAttribute("bList", bList);
//pageMove[0]=forward, pageMove[1]=/board/boardList.jsp
path = "forward:board/boardList";
}
if("redirect".equals(pageMove[0]))
-> res.sendRedirect("/"+path+".jsp);
== res.sendRedirect(/board/boardList.gd.jsp)
글 쓰기 버튼을 누른 순간
ActionServlet ->
BoardController(boardInsert) ->
HashMapBinder ->
bLogic.boardInsert(pMap) ->
insert부분 처리완료
다시 bLogic.boardInsert result == 1이기 때문에,
path="redirect:/board/boardList.gd2";에 넣는다. 최종 리턴 path를 하고
다시 ActionServlet으로 돌아와서 result에 controller를 담는다.
result = "redirect:board/boardList" 를 담는다.
result가 (:)를 가지고 있을 떄, (sendRedirect와, forward가 이에 해당함)
else(그 밖의 경우->(/)로 쪼개야한다.)
그러면 WEB-INF일때만, (/)으로 분기한다.
4-1. 그것을 가지고 조건을 한 번 더 분기한다.
둘 다 아닌 경우에 들어가기 이전,
WEB-INF 파일을 BoardController에서 path 경로를 잡아줄 때, 이것은 String으로 ActionServlet에 리턴한다.
[WEB-INF]
[WebApp]
이렇게 리턴받는게 다르기 때문에 먼저 숙지하고 처리해야된다.
둘 다 아닌 경우(else)
path = pageMove[0]+"/"+pageMove[1]; 를 하게 되는데,
저것을 알맞게 처리하면,
처음에 경우를 나눈 이유가 뭘까?
처음에 else{} 에 걸리고 pageMove = result.split("/");
를 진행한다.
이 때, pageMove에 [0] = board + [1] = boardList 가 분기되어 들어간다. (처음에는 ("/")로 슬라이싱) 하는 if)
두 번째 조건분기 if(pageMove != null) 이 때, path의 경로를 설정하고 forward하기 위한 if문이다.
[원래코드]
else if("noticeDelete".equals(upmu[1])) {//delete
logger.info("noticeDelete");
int result = 0;
hmb.bind(pMap);
result = nLogic.noticeDelete(pMap);
if(result == 1) {
path.append("noticeList.gd");
isRedirect = true;
}else {
path.append("noticeError.jsp");
isRedirect = true;
}
}
[수정코드]
else if("noticeDelete".equals(upmu[1])) {//delete
logger.info("noticeDelete");
int result = 0;
hmb.bind(pMap);
result = bLogic.boardDelete(pMap);
if(result == 1) {//글등록 성공했을때
path="redirect:board/boardList";
}else {
path="redirect:/board/boardError.jsp";
}
}/////// end of boardDelete - 조건문 블록 하나하나가 메소드로 분할될것.
public class BoardDao {
Logger logger = Logger.getLogger(BoardDao.class);
SqlSessionFactory sqlSessionFactory = null;
public BoardDao() {
sqlSessionFactory = MyBatisCommonFactory.getSqlSessionFactory();
}
public class BoardLogic {
Logger logger = Logger.getLogger(BoardLogic.class);
BoardDao bDao = new BoardDao();
public List<Map<String, Object>> boardList(Map<String, Object> pMap) {
logger.info("boardList");
//웹개발에서는 NullPointerException이 발동하면 화면자체가 안열림 - 막막함
//어떤 힌트를 보고 문제를 예측해서(추측) 하나씩 가능성을 제거해 나가는 과정을 통해서 트러블슈팅을 완성함
//화면은 출력이 된다
List<Map<String, Object>> bList = new ArrayList<>();//NullPointerException방어코드로
bList = bDao.boardList(pMap);
return bList;//화면과 로직을 분리하자 - > POJO 설계해 본다
}
//아래 메소드는 트랜잭션처리 대상이다
//업무적인 depth가 깊을 수록 이런상황이 발생된다
//AOP{수평적인 관점 관계설정, 개입, 처리가능하게 지원}(<-> OOP-상하관계)는 프레임워크의 한 종류로 공통된 관심사에 대해서 클래스의 어떤 지점을
//접근하고 추가코드 없이 자동으로 어떤 일 처리를 가능하게 해주는 프로그래밍 기법이다
public int boardInsert(Map<String, Object> pMap) {
logger.info("boardInsert");
int result = 0;
result = bDao.boardInsert(pMap);
//result2 = mDao.memberUpdate(pMap);
return result;
}
public int boardUpdate(Map<String, Object> pMap) {
logger.info("boardUpdate");
int result = 0;
result = bDao.boardUpdate(pMap);
return result;
}
public int boardDelete(Map<String, Object> pMap) {
logger.info("boardDelete");
int result = 0;
result = bDao.boardDelete(pMap);
return result;
}
}
public int boardInsert(Map<String, Object> pMap) {
logger.info("BoardLogic : boardInsert 메소드 안에 진입했습니다.");
int result = 0;
result = bDao.boardInsert(pMap);
// result2 = mDao.memberUpdate(pMap)
return result;
}
result2 = mDao.memberUpdate(pMap) -- 이 부분에서 다른 Dao로 접근한다.트랜잭션 처리 대상이다.
서로 다른 2가지에서 한 쪽에서 insert, delete, 이런식으로 2가지 Dao로 접근한다면 트랜잭션 처리 대상이다. + 즉, 업무적인 depth가 깊을 수록 이런 상황이 발생된다.
[원래코드]
ActionForward af = null;
NoticeController nc = new NoticeController();//결합도가 강하다-별로다-제어역전아니다 - 스프링관계된 포인트
//MemberController mc = new MemberController();
//LectureController lc = new LectureController();
////////////////////////[[ 어떤 컨트롤러를 태울것인가? ]]/////////////////////////
//이 지점은 내려가는 방향이다
if("notice".equals(upmu[0])) {
req.setAttribute("upmu",upmu);
af = nc.execute(req, res);//NoticeController클래스로 건너감 - upmu[1]-메소드이름이니까...
}
if(af !=null) {
if(af.isRedirect()) {//true라는 건 sendRedirect인 경우임
if(af.getPath() == null) {
return;//해당메소드 탈출
}else {
res.sendRedirect(af.getPath());// -> notice/noticeList.jsp
}
}
else{//forward인 경우임 - url안바뀜, 화면은 바뀜, 유지됨. a페이지에서 쥐고 있는 정보를 b페이지에서도 사용가능함
if(af.getPath().contains("/")) {
RequestDispatcher view = req.getRequestDispatcher(af.getPath());
view.forward(req, res);
}
else if(af.getPath() == null) {//파일 업로드 처리시 ActionForward를 통해서 값을 리턴 받을때 문제가 발생됨. 이부분에 대한 해결 프로세스 추가하였다.
logger.info("path가 null일때");
}
else {
logger.info("슬래쉬가 미포함인 경우 ===> " + af.getPath());
res.setCharacterEncoding("utf-8");
res.setContentType("text/plain;utf-8");
PrintWriter out = res.getWriter();
out.print(af.getPath());
logger.info(af.getPath());
return;
}
}
}/////////// end of if - 응답페이지 호출하기 - 포워드
[수정코드]
Controller controller = new BoardController();
if("board".equals(upmu[0]))
{
logger.info("ActionServlet WorkName ==> execute 호출");
req.setAttribute("upmu",upmu);
result = controller.execute(req, res);
}
// board 컨트롤러를 경유한 다음에 리턴값으로 문자열을 받았다.
// 콜론으로 자르고(1) + 슬래시로 자른다(2)
// 1. 널체크하기
// 2. 문자열 배열을 선언할 것,
// 3. 콜론이 포함되어 있니?
// 4. 콜론이 포함되어 있지 않은 경우
if(result != null)
{
logger.info("result 타니?");
String [] pageMove = null;
if(result.contains(":"))
{
pageMove = result.split(":"); // :를 기준으로 나눔
// [0] = redirect [1] = /board/boardList.jsp
// 이 경우에는 슬래시로 한 번더 짤라야된다.
}
else //WEB-INF 경로를 가진 경우 /board/boardList.jsp
{
// 슬래시 기준으로 나눈다.
pageMove = result.split("/");
//[0] = board [1] = boardList.jsp
logger.info(pageMove);
}
logger.info(pageMove[0] + ", " + pageMove[1]);
if(pageMove != null)
{
String path = pageMove[1];
logger.info("pageMove타니?");
if("redirect".equals(pageMove[0]))
{
logger.info("redirect\".equals(pageMove[0] 구역입니다.");
res.sendRedirect("/"+path+".jsp");
}
else if("forward".equals(pageMove[0]))
{
logger.info("forward\"..equals(pageMove[0])");
RequestDispatcher view = req.getRequestDispatcher("/"+path+".jsp");
view.forward(req, res);
}
else {
logger.info("WEB-INF타니?");
path = pageMove[0]+"/"+pageMove[1];
RequestDispatcher view = req.getRequestDispatcher("/WEB-INF/jsp/"+path+".jsp");
view.forward(req, res);
}///// end of 배포위치가 WEB-INF인 경우
}
}
}//end of Service
인터페이스로 -> 인스턴스화
result 리턴 타입이 String
[원래코드]
if(af !=null) {
if(af.isRedirect()) {//true라는 건 sendRedirect인 경우임
if(af.getPath() == null) {
return;//해당메소드 탈출
}else {
res.sendRedirect(af.getPath());// -> notice/noticeList.jsp
}
}
else{//forward인 경우임 - url안바뀜, 화면은 바뀜, 유지됨. a페이지에서 쥐고 있는 정보를 b페이지에서도 사용가능함
if(af.getPath().contains("/")) {
RequestDispatcher view = req.getRequestDispatcher(af.getPath());
view.forward(req, res);
}
else if(af.getPath() == null) {//파일 업로드 처리시 ActionForward를 통해서 값을 리턴 받을때 문제가 발생됨. 이부분에 대한 해결 프로세스 추가하였다.
logger.info("path가 null일때");
}
else {
logger.info("슬래쉬가 미포함인 경우 ===> " + af.getPath());
res.setCharacterEncoding("utf-8");
res.setContentType("text/plain;utf-8");
PrintWriter out = res.getWriter();
out.print(af.getPath());
logger.info(af.getPath());
return;
}
}
}/////////// end of if - 응답페이지 호출하기 - 포워드
[수정코드]
if(result != null)
{
logger.info("result 타니?");
String [] pageMove = null;
if(result.contains(":"))
{
pageMove = result.split(":"); // :를 기준으로 나눔
// [0] = redirect [1] = /board/boardList.jsp
// 이 경우에는 슬래시로 한 번더 짤라야된다.
}
else //WEB-INF 경로를 가진 경우 /board/boardList.jsp
{
// 슬래시 기준으로 나눈다.
pageMove = result.split("/");
//[0] = board [1] = boardList.jsp
logger.info(pageMove);
}
logger.info(pageMove[0] + ", " + pageMove[1]);
if(pageMove != null)
{
String path = pageMove[1];
logger.info("pageMove타니?");
if("redirect".equals(pageMove[0]))
{
logger.info("redirect\".equals(pageMove[0] 구역입니다.");
res.sendRedirect("/"+path+".jsp");
}
else if("forward".equals(pageMove[0]))
{
logger.info("forward\"..equals(pageMove[0])");
RequestDispatcher view = req.getRequestDispatcher("/"+path+".jsp");
view.forward(req, res);
}
else {
logger.info("WEB-INF타니?");
path = pageMove[0]+"/"+pageMove[1];
RequestDispatcher view = req.getRequestDispatcher("/WEB-INF/jsp/"+path+".jsp");
view.forward(req, res);
}///// end of 배포위치가 WEB-INF인 경우
}
}
testCase 1) {webapp- path = "forward:board/boardDetail";
}
testcase 2) WEB-INF이 보고싶으면 BoardListController부분
board/boardDetail
수정하면 된다.