ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • UML: ClassDiagram,SequenceDiagram, Servlet:Filter
    JAVA 2021. 7. 26. 12:56

    UML: Sequence Diagram

    Class Diagram: 정적다이어그램
    Sequence Diagram: 동적다이어그램(시간순서대로)
    // control 의 업무진행 과정을 순서대로 자세히 나타낼 수 있다.

    Class Diagram

    control
    - 메모
    요청사항 + 요청명 + 받는 parameter 기입 'key : value'

    - forward 메모
    1) 보내는 parameter = 'key:value'
    2) 해당사항이 어떤조건인지 '정상' 루트인지 '비정상' 루트인지

    1. Sequence Diagram 작성하기 // 컨트롤들의 내부,외부 순서

    Interactions ( Basic ) : 왼쪽 하단의 Toolbox 탭
    Lifeline (이미 생성한 클래스(control) 을 끌어당겨 놓으면 알아서 lifeline 으로 생성.)
    이름: '객체명 : 클래스명' (control 의 객체명은 딱히 중요치 않으니 "Lifeline1:클래스명" 으로
    Self Message : 이 컨트롤에서 해야 할 업무들(내부에서 검사)
    Message
    이름: 가리킨 것이 control 로, forward 할 때 '해당 컨트롤 요청명'
    가리킨 것이 DAO 로, 그 메서드를 사용할 때 '메서드(매개변수)'
    가리킨 것이 view 로, 'forward(업무 후 추출한 값)'

    1. -- > (Message 선 더블클릭하고 양옆에 뜨는 선택사항중 Add Replay Message) = 메서드 호출 후 받는 return 값
    이름: return 변수명 이니 '변수명'
    해당 return 값이 객체라면 그 클래스를 가져오고 '변수명 : 클래스명' 에 변수명을 똑같이 설정

    2. [] ( Message 선 누르고 오른쪽하단 상세탭에 guard ) : 조건을 나타낼 때 사용.
    Interactions ( Advanced ) : 왼쪽 하단의 Toolbox 탭
    Found Message : 해당 control 의 '메서드(request 가 가지고 온 parameter)' 기입
    해당 message 더블클릭하고 add note : 해당 컨트롤의 요청명 기입

     

    오른쪽의 회원상세업무에 대한 Class Diagram 을 , 왼쪽의 Sequence Diagram 으로 순서대로 자세히 작성

    실제 Sprging 상황. 위의 Sequence Diagram 의 1번 순서와 똑같음.

    @Controller
    public class 회원상세보기 implements IControl{
    @Autowired
    IMemberDAO memberDAO;
    
    @RequestMapping("detail_member")
    	public ModelAndView process(int no) {
      }
    }

    2. 위 작성을 토대로 코드작성(설계서 그대로 해보기)

    >> 회원상세보기.java

    public class 회원상세보기 implements IControl{
    	
    	IMemberDAO memberDAO = new MemberDAO();
    	
    	@Override
    	public ModelAndView process(HttpServletRequest request, HttpServletResponse response) {
    		int 회원번호 = Integer.valueOf(request.getParameter("no"));
    		
    		// 로그인 여부검사
    		boolean 로그인 = false;
    		HttpSession session = request.getSession(false);
    		
    		if(session != null && session.getAttribute("name") != null) {
    			로그인 = true;
    		}
    		
    		ModelAndView mv = new ModelAndView();
    		if(!로그인) {
    			mv.addObject("message", "로그인 후 이용이 가능합니다.");
    			mv.setViewName("forward:/prepare_login.do");
    			return mv;
    		}
    			
    		
    		Member findedMember = memberDAO.findByNo(회원번호);
    			
    		mv.addObject("findedMember", findedMember);
    		mv.setViewName("회원상세창");
    
    		return mv;
    	}
    }
    control 들은 멤버변수없이 메서드만 있는 상태가 없는 클래스다(빈객체=Stateless).
    Spring 에서는 이를 빈객체라 하여 관리해주는 것이다
    이 Spring 에서 빈객체로 선언되면 컨테이너(톰캣서버) 가 실행되어 초기화할 때 같이 데이터가 올라간다.
    그러면 각 요청마다 계속 초기화, 선언해서 속도가 늦춰졌던걸 컨테이너 범위에서 초기화 하므로서 방지할 수 있다.

    >> Profile.java (회원상세창에 띄울 프로필사진을 위해 작업하는 control)

    public class Profile implements IControl{
    
    	IMemberDAO memberDAO = new MemberDAO();
    	
    	@Override
    	public ModelAndView process(HttpServletRequest request, HttpServletResponse response) {
    		int no = Integer.valueOf(request.getParameter("no"));
    		
    		Member member = memberDAO.findByNo(no);
    		ModelAndView mv = new ModelAndView();
    		
    		mv.setViewName("profile");
    		mv.addObject("profile", member.getProfile());
    		return mv;
    	}
    }

    >> profile.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%@ page trimDirectiveWhitespaces="true" %>
    //꼭 기입!!!(자꾸 OutputStream이 이미 읽었다고 뭐라함, 그리고 whitespace가 있다고 한다는데..?)
    <%
    byte[] profile = (byte[])request.getAttribute("profile");
    
    response.setContentType("image/jpeg");
    ServletOutputStream os = response.getOutputStream();
    os.write(profile);
    %>

    >> 회원상세창.jsp

    <body>
    
    <h1>회원상세</h1>
    성명 <input type = "text" id="name" readonly="readonly" value="${findedMember.name}"><br>
    프로필<img src="profile.do?no=${findedMember.no}"/><br>
    우편번호 <input type = "text" id="post" readonly="readonly" value="${findedMember.post}"><br>
    주소 <input type = "text" readonly="readonly" value="${findedMember.address}"> <br>
    상세주소 <input type = "text" readonly="readonly" value="${findedMember.detailaddress}"> <br>
    전화번호 <input type = "text" readonly="readonly" value="${findedMember.tel}"/><br>
    이메일 <input type = "text" readonly="readonly" value="${findedMember.email}"/><br>
    아이디 <input type = "text" readonly="readonly" value="${findedMember.id}"><br>
    
    </body>

    Filter

    Filter 만들기 (LoginFilter 만들기)
    FrontController 보다 먼저 모든(다수Filter 생성가능) Filter 의 doFilter() 를 수행하고 FrontController 로 간다.
    1. HttpServlet 을 상속받아 Http 에서 Tomcat 서버안에 돌아가는 Servlet 을 상속받고
    Filter 를 구현한다.
    2. Login 확인을 위한 코드를 그대로 작성한다.
    - session 같은 경우는 현재 Http 규격이라 HttpSession 이기 때문에 request 도 부모인 ServletRequest 로 얻어지지 않고
    HttpServletRequest 로 형변환 하여 getSession(false) 해야한다.
    - 로그인 안했을 때는 prepare_login.do 컨트롤로 가도록 forward 시킨다.
    추가사항 : String table 로 따로 class 를 만들어 로그인 하지 않았을 때 던지는 message 들을 요청명에 따라 다르게 나오도록 설정할 수 있다.
    // 규격화 된 상황은 아니다.
    3. chain.doFilter(request.response) 작성한다.
    다음 Filter 로 chain 되게하는 방법이다.(끝나면 FrontController 로)
    순서는 현재 filter 에서 로그인여부에 걸린다면 forward 하면서 끝나거나
    현재 filter 에 걸리지않으면 chain.doFilter() 로 다른 filter 들까지 호출하고 이 메서드 끝나면 chain.doFilter() 밑의 코드들을 실행시킨다.
    4-1. web.xml<filter><filter-name> 을 정하고 <filter-class> 로 어디에 있는 필터클래스인지 설정한다.
    4-2. <filter-mapping> 에 위의 <filter-name> 을 가져와 매핑준비하고 <url-pattern> 에 매핑할 컨트롤 주소들을 적는다.

    >> LoginFilter.java

    이제 나머지 control 에 있는 로그인 확인 업무를 다 지워도 된다.

    import javax.servlet.Filter; //javax.servlet 꺼다.
    ...
    
    public class LoginFilter extends HttpServlet implements Filter {
    
        public void init(FilterConfig filterConfig) throws javax.servlet.ServletException { 
        }
    
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, javax.servlet.ServletException { 
        	// 요청전		
        	// HttpSession 을 얻으려면 이 메서드는 ServletRequest 객체이기 때문에 HttpServletRequest 객체로 형변환하여 가져와야한다.
        	// HttpServletRequest 는 ServletRequest 를 상속받았다.
        	HttpSession session = ((HttpServletRequest)request).getSession(false);//없으면 null 값을 준다.
    		boolean 로그인 = false;
    		if (session != null && session.getAttribute("no") != null) {
    			로그인 = true;
    		};
    		
    		if(!로그인)		
    		{
    			request.setAttribute("message", "로그인 후 이용이 가능합니다.");
    			RequestDispatcher rd = request.getRequestDispatcher("prepare_login.do");
    			rd.forward(request, response);
    			return;
    		}
    
        	chain.doFilter(request, response);
        	// 응답전
        }
    
    
    	public void destroy() {
    	}
    
    }

    >> web.xml

    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="2.5">
      <filter>
      	<filter-name>loginFilter</filter-name>
      	<filter-class>com.stone.mvc.env.LoginFilter</filter-class>
      </filter>
      
      <filter-mapping>
      	<filter-name>loginFilter</filter-name>
      	<url-pattern>/prepare_board.do</url-pattern>
      	<url-pattern>/add_board.do</url-pattern>
      	<url-pattern>/detail_member.do</url-pattern>
      </filter-mapping>
    </web-app>

    >> 로그인창.jsp

    만약 로그인 안하고 위 매핑되어 있는 페이지로 가려하면 이렇게 이 로그인창이 뜨며 message 가 넘어와 출력된다.

    <body>
    <h1>로그인</h1>
    <p>${message}</p>
    <form action="login.do" method="post" onsubmit="return 필수입력()">
    id <input type="text" id="id" name="id"/>
    password <input type="password" id="password" name="password"/>
    <input type="submit" value="로그인"/>
    </form>
    </body>

    댓글

Designed by Tistory.