해당 게시글은 MVC 나누기 1, MVC나누기 2 포스팅의 작업을 거쳐 완성된 내용물이다. 따라서 추가된 부분에 대하여만 부분적으로 언급 할 예정이며 이전 코드들과 내용은 각각의 포스팅에서 확인 가능하니 참고할 필요가 있다. 목차는 다음과 같다. 추가로 [controller업그레이드] 부분의 내용들을 적용하여 작업하기 때문에 2개의 게시글을 확인하고 오면 이해가 수월할 것이다.
1. view 수정
2. FrontController
3. 인코딩_Filter
4. 샘플데이터_Listener
해당 프로젝트의 전체 코드를 압축하여 첨부하였다. 설명 생략된 부분과 주석에 대해 더 자세히 확인할 수 있다.
1. view 수정
view의 모든 경로들을 수정하여 특정 url패턴을 부여하여 Front Controller의 파일로 집합시키거나, 혹은 바로 페이지 이동이 될 수 있도록 작업해야한다.
2. FrontController개념 도입
1) servlet
url패턴을 어노테이션으로 설정하고, 해당 파일을 통해 controller의 작업이 필요한 view페이지가 한 번에 모일 수 있도록 작업한다.
package controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class FrontController
*/
@WebServlet("*.do")
public class FrontController extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public FrontController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
actionDo(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
actionDo(request, response);
}
private void actionDo(HttpServletRequest request, HttpServletResponse response) {
String uri=request.getRequestURI();
String cp=request.getContextPath();
String command=uri.substring(cp.length());
ActionForward forward=null;
if(command.equals("/main.do")) {
System.out.println("FC로그: 메인페이지 요청");
try {
forward=new MainAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/login.do")) {
System.out.println("FC로그: 로그인페이지 요청");
try {
forward=new LoginAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/logout.do")) {
System.out.println("FC로그: 로그아웃페이지 요청");
try {
forward=new LogoutAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/board.do")) {
System.out.println("FC로그: 상세페이지 요청");
try {
forward=new BoardAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/insert.do")) {
System.out.println("FC로그: 글작성페이지 요청");
try {
forward=new InsertAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/update.do")) {
System.out.println("FC로그: 글 수정 요청");
try {
forward=new UpdateAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/delete.do")) {
System.out.println("FC로그: 글 삭제 요청");
try {
forward=new DeleteAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/signup.do")) {
System.out.println("FC로그: 회원가입 요청");
try {
forward=new SignupAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/mypage.do")) {
System.out.println("FC로그: 마이페이지 요청");
try {
forward=new MypageAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/mupdate.do")) {
System.out.println("FC로그: 회원정보수정 요청");
try {
forward=new MupdateAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(command.equals("/mdelete.do")) {
System.out.println("FC로그: 회원정보삭제 요청");
try {
forward=new MdeleteAction().execute(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
System.out.println("잘못된 요청");
}
if(forward==null) {
forward=new ActionForward();
forward.setPath("error.jsp");
forward.setRedirect(false);
}
RequestDispatcher dispatcher=request.getRequestDispatcher(forward.getPath());
try {
dispatcher.forward(request, response);
} catch (ServletException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2) POJO
① interface파일
메서드의 input과 output을 강제한다.
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Action {
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception;
}
② 자료형대체파일
interface에서 강제한 추상메서드를 통해 반환할 output으로 어디로, 어떻게 갈지 다른 자료형의 두 아웃풋이 필요하게 되는데, 일반적으로는 두개의 결과를 return할 수 없기때문에 자료형 개념으로 class파일을 생성하였다.
package controller;
public class ActionForward {
//output으로 사용할 멤버변수
private String path;//어디로
private boolean redirect;//redirect방식인지
//생성자
public ActionForward() {
}
//getter & setter
public String getPath() {
return path;
}
public boolean getRedirect() {
return redirect;
}
public void setPath(String path) {
this.path = path;
}
public void setRedirect(boolean redirect) {
this.redirect = redirect;
}
}
③ implement파일
로그인과 로그아웃에 대한 로직부분의 코드만을 첨부하였다.
로그인 관련 로직
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import member.MemberDAO;
import member.MemberVO;
public class LoginAction implements Action {
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
ActionForward forward=new ActionForward();
MemberDAO dao=new MemberDAO();
MemberVO vo=new MemberVO();
//view에서 받은 입력을 vo에 set
vo.setMid(req.getParameter("mid"));
vo.setMpw(req.getParameter("mpw"));
vo=dao.selectOne(vo);
if(vo==null) {//로그인 실패면
//그냥 로그인페이지로 새로고침
forward.setPath("/a_login.jsp");
forward.setRedirect(true);
}else {//성공이면
//session에 로그인 정보 저장해서
HttpSession session= req.getSession();
session.setAttribute("mname", vo.getMname());
session.setAttribute("mid", vo.getMid());
//메인으로 새로고침
forward.setPath("/main.do");
forward.setRedirect(true);
}
return forward;
}
}
로그아웃 관련 로직
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LogoutAction implements Action {
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
ActionForward forward=new ActionForward();
forward.setPath("/a_login.jsp");
forward.setRedirect(true);
//로그아웃하면 아무것도 가져가지말고 그냥 로그인 페이지로 가
HttpSession session= req.getSession();
session.invalidate();
return forward;
}
}
* session정보는 request.getSession을 통해 받아올 수 있다. *
* ActionForward(output)을 설정할때, 해당 로직의 비정상수행시 오류페이지로 이동인지의 여부에 따라 forward를 null로 표시할 수 있고, 아닐수도 있다. *
3. 인코딩_Filter
① filter파일
package controller;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
/**
* Servlet Filter implementation class EncodingFilter
*/
@WebFilter({ "*.do", "*.jsp" })
public class EncodingFilter extends HttpFilter implements Filter {
private String encoding;
public EncodingFilter() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
System.out.println("필터 수행");
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
this.encoding=fConfig.getServletContext().getInitParameter("encoding");
System.out.println("필터 생성");
}
}
doFilter( )메서드로 인코딩을 진행하고, init( )메서드로 서블릿 최초 동작시 초기화 매개변수인 encoding의 값을 불러오도록 한다.
② 초기화매개변수 설정(xml파일)
encoding이라는 이름의 변수에 UTF-8이라는 값을 세팅
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
</web-app>
4. 샘플데이터_Listener
① 크롤링파일
package controller;
import java.io.IOException;
import java.util.Iterator;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Crawling {
public static String admin;
public static void start() {
final String url="https://www.lyrics.co.kr/?p=472837#gsc.tab=0";
Document doc=null;
try {
doc=Jsoup.connect(url).get();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Elements eles=doc.select("div.blog-content");
Iterator<Element> itr=eles.iterator();
while(itr.hasNext()) {
admin=itr.next().text();
}
}
}
재사용 목적이 없다. static을 통해 외부 파일에서 객체화 없이 즉각적으로 사용이 가능하다.
② 리스너 파일
package controller;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* Application Lifecycle Listener implementation class CrawlingListener
*
*/
@WebListener
public class CrawlingListener implements ServletContextListener {
/**
* Default constructor.
*/
public CrawlingListener() {
// TODO Auto-generated constructor stub
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent sce) {
Crawling.start();
System.out.println("로그: 리스너 클래스: 크롤링 완료");
ServletContext sc=sce.getServletContext();
sc.setAttribute("admin", Crawling.admin);
}
}
크롤링 파일의 데이터들을 불러와 admin이라는 이름으로 setAttribute하였다. 사용할 공간에서 ${admin}을 하여 쉽게 데이터를 불러올 수 있게 된다.
'JSP' 카테고리의 다른 글
[게시판 Ver.2] 커스텀태그_응용 (0) | 2022.03.15 |
---|---|
[게시판 Ver.2] 게시글과 댓글의 화면 출력 (0) | 2022.03.14 |
[controller업그레이드] 리스너 & 필터_(크롤링 & 인코딩) (0) | 2022.03.10 |
[controller업그레이드] 서블릿 활용 (0) | 2022.03.08 |
[View업그레이드] 커스텀 태그 (0) | 2022.03.07 |