현재 관리자가 웹 사이트의 Header 타이틀을 변경하고자 합니다. 이때, 해당 타이틀은 아래의 사진과 같이 왼쪽 상단에 어느 페이지든지 제공되어야 합니다. 또한 관리자가 변경하기 전에 로그인한 유저의 화면에도 변경된 타이틀이 반영되어야 합니다.
해당 Header와 관련된 정보는 아래와 같이 <h1>MySite</h1>
고정된 값으로 받고 있었습니다.
<%@ taglib uri="jakarta.tags.core" prefix="c"%>
<%@ taglib uri="jakarta.tags.fmt" prefix="fmt"%>
<%@ taglib uri="jakarta.tags.functions" prefix="fn"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div id="header">
<h1>MySite</h1>
<ul>
<c:choose>
<c:when test="${empty authUser}" >
<li><a href="${pageContext.request.contextPath}/user/login">로그인</a></li>
<li><a href="${pageContext.request.contextPath}/user/join">회원가입</a></li>
</c:when>
<c:otherwise>
<li><a href="${pageContext.request.contextPath}/user/update">회원정보수정</a></li>
<li><a href="${pageContext.request.contextPath}/user/logout">로그아웃</a></li>
<li>${authUser.name}님 안녕하세요 ^^;</li>
</c:otherwise>
</c:choose>
</ul>
</div>
따라서 2가지의 방법을 사용해서 변경되는 Header의 타이틀을 반영하도록 하겠습니다.
가장 먼저, Interceptor를 생각해볼 수 있습니다. Interceptor는 아래의 사진과 같이 원하는 Controller로 넘어가기 전에 거쳐가는 역할을 합니다. 따라서 Client의 요청인 URL을 보고 나서 원하는 작업이 가능합니다.
즉, 해당 사이트로 들어오는 사용자의 URL마다 title이 업데이트되었는지 확인하며 가져오는 코드를 Interceptor에 추가하여 최신의 title을 가져오도록 할 수 있습니다.
그리고 아래와 같이 spring-servlet.xml 파일에 interceptor를 추가하여 /**처럼 모든 URL마다 해당 interceptor를 적용할 수 있습니다.
해당 코드의 가장 큰 단점으로는 매번 URL 요청마다 siteService.getSite().getTitle()이라는 코드가 실행되면서 쿼리가 항상 실행된다는 점입니다.
따라서 이를 개선하기 위해 타이틀이 수정될 때에만 쿼리를 요청하는 방법으로 수정해야 합니다.
따라서 ServletContext의 Attribute Map에 타이틀이 있는지 확인하고 없으면 쿼리문을 실행하고, 있으면 기존의 타이틀을 가져오도록 구현할 수 있습니다. 이때, 타이틀을 siteVo라는 객체에 담아 표현하였습니다.
가장 먼저, spring-servlet.xml의 interceptors에 SiteInterceptor를 추가해줍니다.
<!-- Interceptors -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"></mvc:mapping>
<mvc:exclude-mapping path="/assets/**"></mvc:exclude-mapping>
<bean class="mysite.interceptor.SiteInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
그리고 아래의 코드에서 본격적으로 SiteInterceptor를 작성합니다. 이때 ServletContext에 siteVo가 있는지 확인하고 없으면 쿼리를 수행하여 siteVo를 가져오는 코드를 실행합니다.
public class SiteInterceptor implements HandlerInterceptor {
private SiteService siteService;
public SiteInterceptor(SiteService siteService) {
this.siteService = siteService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
SiteVo siteVo = (SiteVo) request.getServletContext().getAttribute("siteVo");
if(siteVo == null) { // siteVo가 ServletContext's Attribute Map이 없는 경우 세팅
siteVo = siteService.getSite();
request.getServletContext().setAttribute("siteVo", siteVo);
}
return true;
}
}
마지막으로 관리자가 타이틀과 같은 사이트 정보를 수정할 때 ServletContext의 siteVo를 수정해줍니다. servletContext.setAttribute("siteVo", siteVo)
@Auth(role = "ADMIN")
@Controller
@RequestMapping("/admin")
public class AdminController {
private final SiteService siteService;
private final FileUploadService fileUploadService;
private final ServletContext servletContext;
public AdminController(SiteService siteService, ServletContext servletContext, FileUploadService fileUploadService) {
this.siteService = siteService;
this.servletContext = servletContext;
this.fileUploadService = fileUploadService;
}
@RequestMapping("/main/update")
public String date(
@RequestParam("title") String title,
@RequestParam("welcomeMessage") String welcomeMessage,
@RequestParam("description") String description,
@RequestParam("file1") MultipartFile file) {
String url = Optional.ofNullable(fileUploadService.restore(file)).orElse("");
SiteVo siteVo = new SiteVo();
siteVo.setDescription(description);
siteVo.setProfile(url);
siteVo.setWelcome(welcomeMessage);
siteVo.setTitle(title);
siteService.updateSite(siteVo);
servletContext.setAttribute("siteVo", siteVo);
return "redirect:/admin";
}
}
그리고 헤더 관련 jsp에서 해당 siteVo.title를 출력할 수 있습니다.
<h1>${siteVo.title }</h1>
<%@ taglib uri="jakarta.tags.core" prefix="c"%>
<%@ taglib uri="jakarta.tags.fmt" prefix="fmt"%>
<%@ taglib uri="jakarta.tags.functions" prefix="fn"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div id="header">
<h1>${siteVo.title }</h1>
<ul>
<c:choose>
<c:when test="${empty authUser}" >
<li><a href="${pageContext.request.contextPath}/user/login">로그인</a></li>
<li><a href="${pageContext.request.contextPath}/user/join">회원가입</a></li>
</c:when>
<c:otherwise>
<li><a href="${pageContext.request.contextPath}/user/update">회원정보수정</a></li>
<li><a href="${pageContext.request.contextPath}/user/logout">로그아웃</a></li>
<li>${authUser.name}님 안녕하세요 ^^;</li>
</c:otherwise>
</c:choose>
</ul>
</div>