Spring 예제#1 ( +Servlet, JSP, FrontController )
2024. 8. 29. 13:35ㆍJAVA 기반 웹개발/SERVLET & JSP
회원 생성 및 조회 예제
FrontController 목적
- 각각의 Controller마다 공통적인 부분을 처리 및 Servlet의 종속된 코드 수정 필요
- 문제)
- jsp 페이지 경로 (중복되는 부분)
- dispatcher.forward의 반복
- Controller에서 잘 사용되지 않는, HttpServletRequest + HttpServletResponse (Servlet 종속)
- Model , View, Controller 분리된 코드의 필요성
- 문제)
- View의 영역에서도 jsp의 forward을 공통적으로 계속해서 처리해줘야했음
- jsp 이름의 공통적인 부분을 viewResolver()를 이용하여 처리
- MyView클래스를 이용하여 forward 하는 부분을 공통적으로 처리할 수 있도록 수정
- HttpServletRequest 및 HttpServletResponse의 종속성을 최대한 줄이는 목적 (Controller에서 사용안할때도 많음)
- 데이터 저장 및 전달의 역할은 ModelView의 Map(String, Object)을 이용
- MyView 클래스의 modelToRequestAttribute() 에서 마지막에 ModelView에서 사용되던 데이터 Object를 request.setAttribute를 이용하여 request로 전달
Front-Controller 도식화
Model 생성
- Model 역할로서 데이터를 전달하는 역할
- 추가로, View 이름까지 전달하는 역할
- View 페이지 이름 저장
- Map을 통해 필요한 데이터값 저장 (데이터는 객체 형태) -> request.getParameter + request.setParameter 처럼 사용 목적
- 예시) Key("member") , value( [Member 객체] )
public class ModelView{
private String viewName;
private Map<String, Object> model = new HashMap<>();
public ModelView(String viewName) {
this.viewName = viewName;
}
public String getViewName() {
return viewName;
}
public void setViewName(String viewName){
this.viewName = viewName;
}
public Map<String,Object> getModel() {
return model;
}
public void setModel(Map<String, Object> model){
this.model = model;
}
}
Controller 로직을 위한 인터페이스
- HttpServlet의 service() 부분과 유사한 Controller 로직 실행 구간 추상화
- 실제로 paramMap에는 request.getParameter("name") 처럼 사용 목적
- 예시) Key(name) , value([폼에서 넘어온 이름])
public interface Controller{
ModelView process(Map<String, String> paramMap);
}
Controller 생성
- view 이름 지정
- paramMap을 통해 데이터를 처리 -> request.getParameter + request.setParameter 처럼 사용 목적
//new-form Controller
public class MeberFormController implements Controller{
@Override
public ModelView process(Map<String, String> paramMap){
return new ModelView("new-form");
}
}
//save Controller
public class MemberSaveController implements Controller{
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelVIew process(Map<String, String> paramMap){
String name = paramMap.get("name");
int age = Integer.parseInt(paramMap.get("age"));
Member member = new Member(name, age);
memberRepository.save(member);
ModelView mv = new ModelView("save-result");
mv.getModel().put("member", member);
return mv;
}
}
//list Controller
public class MemberListController implements Controller{
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap){
List<Member> members = memberRepository.findAll();
ModelView mv = new ModelView("members");
mv.getModel().put("members", members);
return mv;
}
}
FrontController 생성
- FrontController 생성 당시 ControllerMap 초기화 ( Controller 맵핑 준비 )
- 요청에서 들어온 URL을 통해 맞는 Controller을 호출 (맵핑 진행)
- Controller을 특정했으면, 요청에 들어온 데이터를 ParamMap에 저장
- ParamMap을 Controller로 보내고 로직 실행
- MyView를 이용하여 렌더링
@WebServlet(urlPatterns="/main/*")
public class FrontControllerServlet extends HttpServlet{
private Map<String, Controller> controllerMap = new HashMap<>();
// 필요한 ViewName 초기화 (Controller 조회 Map)
public FrontControllerServlet(){
controllerMap.put("/main/new-form", new MemberFormController());
controllerMap.put("/main/save", new MemberSaveController());
controllerMap.put("/main/members", new MemberListController());
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
String requestURI = request.getRequestURI();
// 요청 URL -> 해당 controller controllerMap에서 꺼내기
Controller controller = controllerMap.get(requestURI);
if(controller == null)
{
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
//request의 요청에 맞는 parameter 생성
Map<String, String> paramMap = createParamMap(request);
//controller에 파라미터를 넘겨서 로직 수행
ModelView mv = controller.process(paramMap);
// controller에서 데이터 처리한 ModelView를 이용하여 MyView로 전송 (jsp 호출)
String viewName = mv.getViewName();
MyView view = viewResolver(viewName);
view.render(mv.getModel(), request, response);
}
private Map<String, String> createParamMap(HttpServletRequest request){
Map<String, String>paramMap = new HashMap<>();
request.getParameterNames()
.asIterator()
.forEachRemaining( paramName -> paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
}
private MyView viewResolver(String viewName){
return new MyView("/WEB-INF/" + viewName + ".jsp");
}
}
View 생성
- jsp로 forward 해주는 역할
- jsp페이지로 넘어가기전에 paramMap에 들어있던 model 객체를 Request에 저장함 -> modelToRequestAttribute
public class MyView{
private String viewPath;
public MyView(String viewPath) {
this.viewPath = viewPath;
}
public void render(HttpServletRequest request, HttpServletResponse response)
throws ServletExcetpion,IOException{
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
throws ServletExcetpion,IOException{
modelToRequestAttribute(model,request);
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
private void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
model.forEach( (key,value) -> request.setAttribute(key, value));
}
}
부가적인 코드
- Member, MemberRepository
public class Member {
private Long id;
private String name;
private int age;
public Member(){
}
public Member(String name, int age){
this.name = name;
this.age = age;
}
//Getter,Setter
}
public class MemberRepository {
private Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
private static final MemberRepository instance = new MemberRepository();
private MemberRepository(){
}
public static MemberRepository getInstance(){
return instance;
}
public Member save(Member member){
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
public Member findById(Long id){
return store.get(id);
}
public List<Member> findAll(){
return new ArrayList<>(store.values());
}
public void clearStore(){
store.clear();
}
}
- new-form / list / save JSP 파일
<!-- /WEB-INF/members.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/index.html">메인</a>
<table>
<thread>
<th>id</th>
<th>username</th>
<th>age</th>
</thread>
<tbody>
<c:forEach var="item" items="${members}">
<tr>
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.age}</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
<!-- /WEB-INF/new-form -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="save" method="post">
name: <input type="text" name="name" /> age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
</body>
</html>
<!-- /WEB-INF/save -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
</head>
<body> 성공 <ul>
<li>id=${member.id}</li>
<li>username=${member.name}</li>
<li>age=${member.age}</li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>
'JAVA 기반 웹개발 > SERVLET & JSP' 카테고리의 다른 글
Spring 예제#2 ( Adapter Handler, FrontController ) (0) | 2024.08.29 |
---|---|
MVC 패턴 ( Servlet + JSP ) (1) | 2024.08.28 |
순수 JSP 예제 (1) | 2024.08.28 |
JSP 이론 및 기초 문법 (1) | 2024.08.28 |