Некоторые нестандартные операционные решения для ServletRequest в Java Web

Spring Boot задняя часть

servletrequest.png

1. Введение

ServletRequestэто мыJava Webчасто связываютсяServlet Api. Иногда нам приходится часто выполнять над ним некоторые операции. Вот некоторые часто трудные операции.

2. Извлеките данные из тела

Для интерфейсных и внутренних взаимодействий мы будемbodyпередать данные. Как мы получаем отbodyизвлечь данные. Обычно мы проходимIOработать:

   /**
      * obtain request body
      *
      * @param request the ServletRequest
      * @return body string   it maybe is   null
      */
     public static String obtainBody(ServletRequest request) {
         
         BufferedReader br = null;
         StringBuilder sb = new StringBuilder();
 
         try {
             br = request.getReader();
             String str;
             while ((str = br.readLine()) != null) {
                 sb.append(str);
             }
             br.close();
         } catch (IOException e) {
             log.error(" requestBody read error");
         } finally {
             if (null != br) {
                 try {
                     br.close();
                 } catch (IOException e) {
                     log.error(" close io error");
                 }
             }
         }
         return sb.toString();
 
     }

Выглядит грязно, с различной обработкой исключений,IOПереключение операции, очень неэлегантно. если вы использовалиJava 8Вы можете упростить эту операцию следующим образом:

         String body = request.getReader().lines().collect(Collectors.joining()); 

BufferedReaderобеспечивает доступ кJava 8 Streamпроточный методlines(), мы можем легко получитьServletRequestсерединаbody

3. Потоки в ServletRequest одноразовые

Не думайте, что выше читаетсяbodyОперация безупречна, здесь есть дыра.Если вы будете следовать вышеизложенномуServletRequestсерединаbodyчитать только один раз. Все данные, которые мы передаем, передаются через потоки.ServletRequestв котором мы фактически переходим:

  ServletInputStream inputStream = request.getInputStream()

чтобы получить входной поток, затем передайтеreadряд методов для чтения.JavaсерединаInputStream readВнутри метода естьpostion, ** Его функция состоит в том, чтобы отметить позицию, прочитанную текущим потоком.Каждый раз при чтении позиция будет перемещаться один раз.Если она прочитана до конца,readметод вернет-1, флаг был прочитан, если вы хотите прочитать его снова, вы можете позвонитьresetметод,positionперейдет к последнему звонкуmarkпозиция,markПо умолчанию0, так что вы можете начать сначала. могуresetусловно, зависит отmarkSupported(),markSupported()Можно ли выполнить возврат методаmark/reset.

давайте оглянемся назадServletInputStream, реализация которого не отменяетresetметод не поддерживаетсяmark/reset. такServletRequestсерединаIO流можно прочитать только один раз.

4. Повторяемый поток чтения в ServletRequest

Если мы используем несколькоServlet FilterСовершайте связанные вызовы и работайте несколько разServletRequestЧто делать с потоком в ? мы можем пройтиServlet Apiкоторый предоставилjavax.servlet.http.HttpServletRequestWrapperупаковать его. по наследствуHttpServletRequestWrapper :


public class ReaderRequest extends HttpServletRequestWrapper {
   private String body;

   public ReaderRequest(HttpServletRequest request) throws IOException {
       super(request);

       body = request.getReader().lines().collect(Collectors.joining());

   }

   @Override
   public BufferedReader getReader() throws IOException {
       final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
       InputStreamReader inputStreamReader = new InputStreamReader(byteArrayInputStream);
       return new BufferedReader(inputStreamReader);
   }
}

Следующее находится вServlet FilterСтандартный пример в:

public class TestFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
         // 包装
        ReaderRequest cachingRequestWrapper=new ReaderRequest((HttpServletRequest) servletRequest);
        // 直接从包装读取
        String collect = cachingRequestWrapper.getReader().lines().collect(Collectors.joining());
        // 传递包装
        filterChain.doFilter(cachingRequestWrapper, servletResponse);
    }
}

5. Как установитьParameter() в ServletRequest

Когда данные передаются с переднего плана, фон проходитHttpServletRequestсерединаgetParameter(String name)способ получения данных. Если фон хочет поместить в него данные, его можно использовать только в следующем запросе или другом запросе.setAttribute(String name, Object o)вставить, а затем изgetAttribute(String name)получить, потерпеть неудачуgetParameter(String name)Получать. я здесьПрактичные галантереи Spring Security: поэкспериментируйте с пользовательским входом в системутолько что столкнулся с этой проблемой

Сначала позвольте мне сказатьgetParameter(String name)Действителен после отправки данных от клиента на сервер, при этом это внутреннее дело сервера, только при вызове сервераsetAttribute(String name, Object o)после этого и редиректа нет(redirect), до поступления к клиентуgetAttribute(String name)чтобы быть эффективными.

Если мы хотим использовать setParameter() в процессе передачи сервера, мы можем передатьgetParameter(String name)ПорученоgetAttribute(String name)выполнить. Соответствующая реализация все еще проходитjavax.servlet.http.HttpServletRequestWrapperреализовать.

  package cn.felord.spring.security.filter;
  
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletRequestWrapper;
  
  /**
   * @author Felordcn
   * @since 2019/10/17 22:09
   */
  public class ParameterRequestWrapper extends HttpServletRequestWrapper {
  
  
      public ParameterRequestWrapper(HttpServletRequest request ) {
          super(request);
  
      }
  
      @Override
      public String getParameter(String name) {
         return (String) super.getAttribute(name);
      }
  }

Вы также можете учиться на идеях для достижения других необходимых вам функций.

6. Резюме

Сегодня мыServletRequestОбъяснены некоторые часто используемые операции. Это также некоторые проблемы, с которыми мы часто сталкиваемся в реальной разработке. Конечно, вы также можете использовать некоторые сторонние пакеты для решения этих проблем.

关注公众号:Felordcn获取更多资讯

Личный блог: https://felord.cn