code: public static String getEncodedServletURI(HttpServletRequest request)
  	{
  		final String servletPath = request.getServletPath();
  		final String contextPath = request.getContextPath();
  		if (servletPath.length() <= 1)
  		{
  			// '' or '/'
  			return contextPath + servletPath;
  		}
  
  		// servletPath has more than one character (first must be '/')
  		final int contextPathLen = contextPath.length();
  		final String requestURI = request.getRequestURI();
  		final char[] requestUriChars = requestURI.toCharArray();
  		final StringBuilder servletURI = new StringBuilder(contextPath);
  		// start index just after context path for matching servletPath
  		int requestUriCharIndex = contextPathLen;
  		/*
  		 * The servletPath is in decoded form, so we use the requestURI to get the corresponding
  		 * encoding form
  		 */
  		for (char ch : servletPath.toCharArray())
  		{
  			if (ch == '/')
  			{
  				/*
  				 * New path fragment found in servletPath Add all chars in corresponding (encoded)
  				 * path fragment from requestURI
  				 */
  				requestUriCharIndex = copyPathFragment(requestUriChars, requestUriCharIndex, servletURI);
  				servletURI.append('/');
  				requestUriCharIndex += 1;
  			}
  		}
  
  		// Add remaining characters
  		requestUriCharIndex = copyPathFragment(requestUriChars, requestUriCharIndex, servletURI);
  		return servletURI.toString();
  	}
docs: Get request's servlet URI encoded, based on results from {@link HttpServletRequest#getContextPath()}
  and {@link HttpServletRequest#getRequestURI()} which are both encoded URI/path, and
  {@link HttpServletRequest#getServletPath()} which is DECODED path. We cannot just concatenate
  context path and servlet path to get the proper result because of these encoding/decoding
  differences, especially if the Servlet path contains encoded characters.
  @param request
  @return servlet URI (meant to be equivalent to contextPath + URLEncoded(servletPath))