首页

关于springframework框架spring-web包HtmlUtils页面工具类进行字符串加密解密htmlEscape/htmlUnescape等处理源码说明

标签:spring-web,HtmlUtils,页面工具类,字符串加密解密,htmlEscape,htmlUnescape,springframework     发布时间:2018-09-15   

一、前言

关于springframework框架spring-web包(4.1.4)的org.springframework.web.util.HtmlUtils页面工具类,进行对html字符串进行加密htmlEscape伪码、对加密html字符串进行解密htmlUnescape等处理。

二、源码说明

1. HtmlUtils类

package org.springframework.web.util;@b@@b@import org.springframework.util.Assert;@b@@b@public abstract class HtmlUtils@b@{@b@  private static final HtmlCharacterEntityReferences characterEntityReferences = new HtmlCharacterEntityReferences();@b@@b@  public static String htmlEscape(String input)@b@  {@b@    return htmlEscape(input, "ISO-8859-1");@b@  }@b@@b@  public static String htmlEscape(String input, String encoding)@b@  {@b@    Assert.notNull(encoding, "Encoding is required");@b@    if (input == null)@b@      return null;@b@@b@    StringBuilder escaped = new StringBuilder(input.length() * 2);@b@    for (int i = 0; i < input.length(); ++i) {@b@      char character = input.charAt(i);@b@      String reference = characterEntityReferences.convertToReference(character, encoding);@b@      if (reference != null) {@b@        escaped.append(reference);@b@      }@b@      else@b@        escaped.append(character);@b@    }@b@@b@    return escaped.toString();@b@  }@b@@b@  public static String htmlEscapeDecimal(String input)@b@  {@b@    return htmlEscapeDecimal(input, "ISO-8859-1");@b@  }@b@@b@  public static String htmlEscapeDecimal(String input, String encoding)@b@  {@b@    Assert.notNull(encoding, "Encoding is required");@b@    if (input == null)@b@      return null;@b@@b@    StringBuilder escaped = new StringBuilder(input.length() * 2);@b@    for (int i = 0; i < input.length(); ++i) {@b@      char character = input.charAt(i);@b@      if (characterEntityReferences.isMappedToReference(character, encoding)) {@b@        escaped.append("&#");@b@        escaped.append(character);@b@        escaped.append(';');@b@      }@b@      else {@b@        escaped.append(character);@b@      }@b@    }@b@    return escaped.toString();@b@  }@b@@b@  public static String htmlEscapeHex(String input)@b@  {@b@    return htmlEscapeHex(input, "ISO-8859-1");@b@  }@b@@b@  public static String htmlEscapeHex(String input, String encoding)@b@  {@b@    Assert.notNull(encoding, "Encoding is required");@b@    if (input == null)@b@      return null;@b@@b@    StringBuilder escaped = new StringBuilder(input.length() * 2);@b@    for (int i = 0; i < input.length(); ++i) {@b@      char character = input.charAt(i);@b@      if (characterEntityReferences.isMappedToReference(character, encoding)) {@b@        escaped.append("&#x");@b@        escaped.append(Integer.toString(character, 16));@b@        escaped.append(';');@b@      }@b@      else {@b@        escaped.append(character);@b@      }@b@    }@b@    return escaped.toString();@b@  }@b@@b@  public static String htmlUnescape(String input)@b@  {@b@    if (input == null)@b@      return null;@b@@b@    return new HtmlCharacterEntityDecoder(characterEntityReferences, input).decode();@b@  }@b@}

2.HtmlCharacterEntityReferences、HtmlCharacterEntityDecoder类

package org.springframework.web.util;@b@@b@import java.io.IOException;@b@import java.io.InputStream;@b@import java.util.Enumeration;@b@import java.util.HashMap;@b@import java.util.Map;@b@import java.util.Properties;@b@import org.springframework.util.Assert;@b@@b@class HtmlCharacterEntityReferences@b@{@b@  private static final String PROPERTIES_FILE = "HtmlCharacterEntityReferences.properties";@b@  static final char REFERENCE_START = 38;@b@  static final String DECIMAL_REFERENCE_START = "&#";@b@  static final String HEX_REFERENCE_START = "&#x";@b@  static final char REFERENCE_END = 59;@b@  static final char CHAR_NULL = 65535;@b@  private final String[] characterToEntityReferenceMap = new String[3000];@b@  private final Map<String, Character> entityReferenceToCharacterMap = new HashMap(252);@b@@b@  public HtmlCharacterEntityReferences()@b@  {@b@    Properties entityReferences = new Properties();@b@@b@    InputStream is = HtmlCharacterEntityReferences.class.getResourceAsStream("HtmlCharacterEntityReferences.properties");@b@    if (is == null)@b@      throw new IllegalStateException("Cannot find reference definition file [HtmlCharacterEntityReferences.properties] as class path resource");@b@    try@b@    {@b@      try@b@      {@b@        entityReferences.load(is);@b@@b@        is.close(); } finally { is.close();@b@      }@b@    }@b@    catch (IOException ex)@b@    {@b@      throw new IllegalStateException("Failed to parse reference definition file [HtmlCharacterEntityReferences.properties]: " + ex@b@        .getMessage());@b@    }@b@@b@    Enumeration keys = entityReferences.propertyNames();@b@    while (keys.hasMoreElements()) {@b@      String key = (String)keys.nextElement();@b@      int referredChar = Integer.parseInt(key);@b@      Assert.isTrue(((referredChar < 1000) || ((referredChar >= 8000) && (referredChar < 10000))) ? 1 : false, "Invalid reference to special HTML entity: " + referredChar);@b@@b@      int index = (referredChar < 1000) ? referredChar : referredChar - 7000;@b@      String reference = entityReferences.getProperty(key);@b@      this.characterToEntityReferenceMap[index] = '&' + reference + ';';@b@      this.entityReferenceToCharacterMap.put(reference, Character.valueOf((char)referredChar));@b@    }@b@  }@b@@b@  public int getSupportedReferenceCount()@b@  {@b@    return this.entityReferenceToCharacterMap.size();@b@  }@b@@b@  public boolean isMappedToReference(char character)@b@  {@b@    return isMappedToReference(character, "ISO-8859-1");@b@  }@b@@b@  public boolean isMappedToReference(char character, String encoding)@b@  {@b@    return (convertToReference(character, encoding) != null);@b@  }@b@@b@  public String convertToReference(char character)@b@  {@b@    return convertToReference(character, "ISO-8859-1");@b@  }@b@@b@  public String convertToReference(char character, String encoding)@b@  {@b@    if (encoding.startsWith("UTF-")) {@b@      switch (character)@b@      {@b@      case '<':@b@        return "&lt;";@b@      case '>':@b@        return "&gt;";@b@      case '"':@b@        return "&quot;";@b@      case '&':@b@        return "&amp;";@b@      case '\'':@b@        return "&#39;";@b@      }@b@    }@b@    else if ((character < 1000) || ((character >= 8000) && (character < 10000))) {@b@      int index = (character < 1000) ? character : character - 7000;@b@      String entityReference = this.characterToEntityReferenceMap[index];@b@      if (entityReference != null)@b@        return entityReference;@b@    }@b@@b@    return null;@b@  }@b@@b@  public char convertToCharacter(String entityReference)@b@  {@b@    Character referredCharacter = (Character)this.entityReferenceToCharacterMap.get(entityReference);@b@    if (referredCharacter != null)@b@      return referredCharacter.charValue();@b@@b@    return 65535;@b@  }@b@}
package org.springframework.web.util;@b@@b@class HtmlCharacterEntityDecoder@b@{@b@  private static final int MAX_REFERENCE_SIZE = 10;@b@  private final HtmlCharacterEntityReferences characterEntityReferences;@b@  private final String originalMessage;@b@  private final StringBuilder decodedMessage;@b@  private int currentPosition = 0;@b@  private int nextPotentialReferencePosition = -1;@b@  private int nextSemicolonPosition = -2;@b@@b@  public HtmlCharacterEntityDecoder(HtmlCharacterEntityReferences characterEntityReferences, String original)@b@  {@b@    this.characterEntityReferences = characterEntityReferences;@b@    this.originalMessage = original;@b@    this.decodedMessage = new StringBuilder(original.length());@b@  }@b@@b@  public String decode()@b@  {@b@    while (this.currentPosition < this.originalMessage.length()) {@b@      findNextPotentialReference(this.currentPosition);@b@      copyCharactersTillPotentialReference();@b@      processPossibleReference();@b@    }@b@    return this.decodedMessage.toString();@b@  }@b@@b@  private void findNextPotentialReference(int startPosition) {@b@    this.nextPotentialReferencePosition = Math.max(startPosition, this.nextSemicolonPosition - 10);@b@    do@b@    {@b@      this.nextPotentialReferencePosition = this.originalMessage@b@        .indexOf(38, this.nextPotentialReferencePosition);@b@@b@      if ((this.nextSemicolonPosition != -1) && (this.nextSemicolonPosition < this.nextPotentialReferencePosition))@b@      {@b@        this.nextSemicolonPosition = this.originalMessage.indexOf(59, this.nextPotentialReferencePosition + 1);@b@      }@b@      boolean isPotentialReference = (this.nextPotentialReferencePosition != -1) && (this.nextSemicolonPosition != -1) && (this.nextPotentialReferencePosition - this.nextSemicolonPosition < 10);@b@@b@      if (isPotentialReference)@b@        return;@b@@b@      if (this.nextPotentialReferencePosition == -1)@b@        return;@b@@b@      if (this.nextSemicolonPosition == -1) {@b@        this.nextPotentialReferencePosition = -1;@b@        return;@b@      }@b@@b@      this.nextPotentialReferencePosition += 1;@b@    }@b@    while (this.nextPotentialReferencePosition != -1);@b@  }@b@@b@  private void copyCharactersTillPotentialReference() {@b@    if (this.nextPotentialReferencePosition != this.currentPosition)@b@    {@b@      int skipUntilIndex = (this.nextPotentialReferencePosition != -1) ? this.nextPotentialReferencePosition : this.originalMessage@b@        .length();@b@      if (skipUntilIndex - this.currentPosition > 3) {@b@        this.decodedMessage.append(this.originalMessage.substring(this.currentPosition, skipUntilIndex));@b@        this.currentPosition = skipUntilIndex;@b@      }@b@      else {@b@        while (this.currentPosition < skipUntilIndex)@b@          this.decodedMessage.append(this.originalMessage.charAt(this.currentPosition++));@b@      }@b@    }@b@  }@b@@b@  private void processPossibleReference() {@b@    if (this.nextPotentialReferencePosition != -1) {@b@      boolean isNumberedReference = this.originalMessage.charAt(this.currentPosition + 1) == '#';@b@      boolean wasProcessable = (isNumberedReference) ? processNumberedReference() : processNamedReference();@b@      if (wasProcessable) {@b@        this.currentPosition = (this.nextSemicolonPosition + 1);@b@      }@b@      else {@b@        char currentChar = this.originalMessage.charAt(this.currentPosition);@b@        this.decodedMessage.append(currentChar);@b@        this.currentPosition += 1;@b@      }@b@    }@b@  }@b@@b@  private boolean processNumberedReference() {@b@    char referenceChar = this.originalMessage.charAt(this.nextPotentialReferencePosition + 2);@b@    boolean isHexNumberedReference = (referenceChar == 'x') || (referenceChar == 'X');@b@    try@b@    {@b@      int value = (!(isHexNumberedReference)) ? @b@        Integer.parseInt(getReferenceSubstring(2))@b@         : @b@        Integer.parseInt(getReferenceSubstring(3), @b@        16);@b@      this.decodedMessage.append((char)value);@b@      return true;@b@    } catch (NumberFormatException ex) {@b@    }@b@    return false;@b@  }@b@@b@  private boolean processNamedReference()@b@  {@b@    String referenceName = getReferenceSubstring(1);@b@    char mappedCharacter = this.characterEntityReferences.convertToCharacter(referenceName);@b@    if (mappedCharacter != 65535) {@b@      this.decodedMessage.append(mappedCharacter);@b@      return true;@b@    }@b@    return false;@b@  }@b@@b@  private String getReferenceSubstring(int referenceOffset) {@b@    return this.originalMessage.substring(this.nextPotentialReferencePosition + referenceOffset, this.nextSemicolonPosition);@b@  }@b@}