Java tutorial
/******************************************************************************* * Copyright (C) 2018 hankai * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ******************************************************************************/ package ren.hankai.cordwood.web.breadcrumb; import org.apache.commons.lang3.StringUtils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * <p>??????????? * <b>NavigationItem</b> ????<b>?</b> * {@link BreadCrumbInterceptor#BREAD_CRUMB_LINKS BREAD_CRUMB_LINKS} ?? * {@link BreadCrumbInterceptor#CURRENT_BREAD_CRUMB CURRENT_BREAD_CRUMB} ????</p> * <p>??{} </p> * * <pre> * "" * "" <=> LinkedHashMap { * "" <=> BreadCrumbLink("", "", true, null) * } * * ?? * "(family)" <=> LinkedHashMap { * "?" <=> BreadCrumbLink("", "?", true, ""), * "" <=> BreadCrumbLink("", "", false, null) * } * * ? * "(family)" <=> LinkedHashMap { * "(label)" <=> BreadCrumbLink("", "", true, "?"), * "?(label)" <=> BreadCrumbLink("", "?", false, ""), * "(label)" <=> BreadCrumbLink("", "", false, null) * } * * ????? \ ? \ <b></b> * * ?? * "(family)" <=> LinkedHashMap { * "?" <=> BreadCrumbLink("", "?", true, ""), * "" <=> BreadCrumbLink("", "", false, null) * } * </pre> * * @author hankai * @version 1.0.0 * @since Dec 6, 2016 2:56:50 PM * @see ren.hankai.cordwood.web.breadcrumb.NavigationItem * @see ren.hankai.cordwood.web.breadcrumb.BreadCrumbLink */ public class BreadCrumbInterceptor implements HandlerInterceptor { /** * ?? <code>Map<String, LinkedHashMap<String, BreadCrumbLink>></code> */ public static final String BREAD_CRUMB_LINKS = "breadCrumb"; /** * ?? <code>LinkedList<BreadCrumbLink></code> */ public static final String CURRENT_BREAD_CRUMB = "currentBreadCrumb"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { final Annotation[] declaredAnnotations = getDeclaredAnnotationsForHandler(handler); if ((declaredAnnotations != null) && (declaredAnnotations.length > 0)) { final HttpSession session = request.getSession(); emptyCurrentBreadCrumb(session); for (final Annotation annotation : declaredAnnotations) { if (annotation.annotationType().equals(NavigationItem.class)) { processAnnotation(request, session, annotation); } } } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } private void emptyCurrentBreadCrumb(HttpSession session) { session.setAttribute(CURRENT_BREAD_CRUMB, new LinkedList<BreadCrumbLink>()); } /** * ?HTTPHandler?? * * @param request HTTP * @param session HTTP? * @param annotation handler * @author hankai * @since Nov 22, 2018 3:54:10 PM */ private void processAnnotation(HttpServletRequest request, HttpSession session, Annotation annotation) { final NavigationItem link = (NavigationItem) annotation; final String family = link.family(); Map<String, LinkedHashMap<String, BreadCrumbLink>> breadCrumb = getBreadCrumbLinksFromSession(session); if (breadCrumb == null) { breadCrumb = new HashMap<>(); } LinkedHashMap<String, BreadCrumbLink> familyMap = breadCrumb.get(family); if (familyMap == null) { familyMap = new LinkedHashMap<>(); breadCrumb.put(family, familyMap); } final BreadCrumbLink breadCrumbLink = getBreadCrumbLink(request, link, familyMap); final LinkedList<BreadCrumbLink> currentBreadCrumb = new LinkedList<>(); generateBreadCrumbsRecursively(breadCrumbLink, currentBreadCrumb); session.setAttribute(CURRENT_BREAD_CRUMB, currentBreadCrumb); session.setAttribute(BREAD_CRUMB_LINKS, breadCrumb); } /** * ???? * * @param request HTTP * @param link ? * @param familyMap * @return ?? * @author hankai * @since Nov 22, 2018 3:55:39 PM */ private BreadCrumbLink getBreadCrumbLink(HttpServletRequest request, NavigationItem link, LinkedHashMap<String, BreadCrumbLink> familyMap) { BreadCrumbLink breadCrumbLink; final BreadCrumbLink breadCrumbObject = familyMap.get(link.label()); resetBreadCrumbs(familyMap); if (breadCrumbObject != null) { breadCrumbObject.setCurrentPage(true); breadCrumbLink = breadCrumbObject; } else { breadCrumbLink = new BreadCrumbLink(link.family(), link.label(), true, link.parent()); final StringBuffer relativeUrl = new StringBuffer(request.getRequestURI()); if (StringUtils.isNotEmpty(request.getQueryString())) { relativeUrl.append("?" + request.getQueryString()); } breadCrumbLink.setUrl(relativeUrl.toString()); familyMap.put(link.label(), breadCrumbLink); } createRelationships(familyMap, breadCrumbLink); return breadCrumbLink; } /** * HTTP??? * * @param session HTTP? * @return ??? * @author hankai * @since Nov 22, 2018 3:57:00 PM */ @SuppressWarnings("unchecked") private Map<String, LinkedHashMap<String, BreadCrumbLink>> getBreadCrumbLinksFromSession(HttpSession session) { final Map<String, LinkedHashMap<String, BreadCrumbLink>> breadCrumb = (Map<String, LinkedHashMap<String, BreadCrumbLink>>) session .getAttribute(BREAD_CRUMB_LINKS); return breadCrumb; } /** * ?HTTPHandler * * @param handler HTTPHandler * @return * @author hankai * @since Nov 22, 2018 3:58:22 PM */ private Annotation[] getDeclaredAnnotationsForHandler(Object handler) { if (handler instanceof HandlerMethod) { final HandlerMethod handlerMethod = (HandlerMethod) handler; final Method method = handlerMethod.getMethod(); final Annotation[] declaredAnnotations = method.getDeclaredAnnotations(); return declaredAnnotations; } else { return null; } } /** * ?? * * @param familyMap ? * @author hankai * @since Nov 22, 2018 3:47:13 PM */ private void resetBreadCrumbs(LinkedHashMap<String, BreadCrumbLink> familyMap) { for (final BreadCrumbLink breadCrumbLink : familyMap.values()) { breadCrumbLink.setCurrentPage(false); } } /** * ?? * * @param link * @param breadCrumbLinks ? * @author hankai * @since Nov 22, 2018 3:48:35 PM */ private void generateBreadCrumbsRecursively(BreadCrumbLink link, LinkedList<BreadCrumbLink> breadCrumbLinks) { if (link.getPrevious() != null) { generateBreadCrumbsRecursively(link.getPrevious(), breadCrumbLinks); } breadCrumbLinks.add(link); } /** * * * @param familyMap * @param newLink * @author hankai * @since Nov 22, 2018 3:50:12 PM */ private void createRelationships(LinkedHashMap<String, BreadCrumbLink> familyMap, BreadCrumbLink newLink) { final Collection<BreadCrumbLink> values = familyMap.values(); for (final BreadCrumbLink breadCrumbLink : values) { if (breadCrumbLink.getLabel().equalsIgnoreCase(newLink.getParentKey())) { breadCrumbLink.addNext(newLink); newLink.setPrevious(breadCrumbLink); newLink.setParent(breadCrumbLink); } } } }