Загрузка изображений с клиента на сервер с помощью пользовательского тега JSF

StackOverflow https://stackoverflow.com/questions/6396196

Вопрос

Я хотел бы загрузить изображения в папку на сервере.

Почему-то не могу.Я не понимаю, почему у меня не срабатывает фильтр. И почему файл не загружается.Может ли кто-нибудь взглянуть на мой код и помочь мне найти причину, по которой файлы не загружаются?

Я вставлю все, что сделал до сих пор, чтобы вы помогли мне найти ошибку:

1.Добавлены commons-fileupload-1.2.1.jar и commons-io-1.4.jar в папку lib (автоматически добавляются в путь к классам).

enter image description here

2. Создан XML-файл, который сделает доступной библиотеку тегов (она находится в папке WEB-INF).

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib version="2.0"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
   http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd">
   <namespace>http://corejsf.com</namespace>
   <tag>
      <tag-name>upload</tag-name>
      <component>
         <component-type>javax.faces.Input</component-type>
         <renderer-type>com.corejsf.Upload</renderer-type>
      </component>
   </tag>
</facelet-taglib>

3.Создайте пакет для реализации тега и поместите в него новый пакет с именем com.corejsf;

enter image description here

Вот источник:

package com.corejsf;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.faces.render.Renderer;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;

@FacesRenderer(componentFamily="javax.faces.Input",
   rendererType="com.corejsf.Upload")
public class UploadRenderer extends Renderer {
   public void encodeBegin(FacesContext context, UIComponent component)  
      throws IOException {
      if (!component.isRendered()) return;
      ResponseWriter writer = context.getResponseWriter();

      String clientId = component.getClientId(context);

      writer.startElement("input", component);
      writer.writeAttribute("type", "file", "type");
      writer.writeAttribute("name", clientId, "clientId");
      writer.endElement("input");
      writer.flush();
   }

   public void decode(FacesContext context, UIComponent component) {
      ExternalContext external = context.getExternalContext(); 
      HttpServletRequest request = (HttpServletRequest) external.getRequest();
      String clientId = component.getClientId(context);
      FileItem item = (FileItem) request.getAttribute(clientId);

      Object newValue;
      ValueExpression valueExpr = component.getValueExpression("value");
      if (valueExpr != null) {
         Class<?> valueType = valueExpr.getType(context.getELContext());
         if (valueType == byte[].class) {
            newValue = item.get();
         }
         else if (valueType == InputStream.class) {
            try {
               newValue = item.getInputStream();
            } catch (IOException ex) {
               throw new FacesException(ex);
            }
         }
         else {
            String encoding = request.getCharacterEncoding();
            if (encoding != null)
               try {
                  newValue = item.getString(encoding);
               } catch (UnsupportedEncodingException ex) {
                  newValue = item.getString(); 
               }
            else 
               newValue = item.getString(); 
         }
         ((EditableValueHolder) component).setSubmittedValue(newValue);  
         ((EditableValueHolder) component).setValid(true);  
      }

      Object target = component.getAttributes().get("target");

      if (target != null) {
         File file;
         if (target instanceof File)
            file = (File) target;
         else {
            ServletContext servletContext 
               = (ServletContext) external.getContext();
            String realPath = servletContext.getRealPath(target.toString());
            file = new File(realPath); 
         }

         try { // ugh--write is declared with "throws Exception"
            item.write(file);
         } catch (Exception ex) { 
            throw new FacesException(ex);
         }
      }
   }   
}

4.Затем я добавил фильтр сервлетов, чтобы различать возможность перехвата запросов, и поместил его в тот же пакет, что и реализация пользовательского тега.

enter image description here

Это его источник:

package com.corejsf;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadFilter implements Filter {
   private int sizeThreshold = -1;
   private String repositoryPath;

   public void init(FilterConfig config) throws ServletException {
      repositoryPath = config.getInitParameter(
         "com.corejsf.UploadFilter.repositoryPath");
      try {
         String paramValue = config.getInitParameter(
            "com.corejsf.UploadFilter.sizeThreshold");
         if (paramValue != null) 
            sizeThreshold = Integer.parseInt(paramValue);
      }
      catch (NumberFormatException ex) {
         ServletException servletEx = new ServletException();
         servletEx.initCause(ex);
         throw servletEx;
      }
   }

   public void destroy() {
   }

   public void doFilter(ServletRequest request, 
      ServletResponse response, FilterChain chain) 
      throws IOException, ServletException {

      if (!(request instanceof HttpServletRequest)) {
         chain.doFilter(request, response);
         return;
      }

      HttpServletRequest httpRequest = (HttpServletRequest) request;

      boolean isMultipartContent 
         = ServletFileUpload.isMultipartContent(httpRequest);
      if (!isMultipartContent) {
         chain.doFilter(request, response);
         return;
      }

      DiskFileItemFactory factory = new DiskFileItemFactory();
      if (sizeThreshold >= 0)
         factory.setSizeThreshold(sizeThreshold);
      if (repositoryPath != null) 
         factory.setRepository(new File(repositoryPath));
      ServletFileUpload upload = new ServletFileUpload(factory);

      try {
         @SuppressWarnings("unchecked") List<FileItem> items 
            = (List<FileItem>) upload.parseRequest(httpRequest);
         final Map<String, String[]> map = new HashMap<String, String[]>();
         for (FileItem item : items) {
            String str = item.getString();
            if (item.isFormField())
               map.put(item.getFieldName(), new String[] { str });
            else
               httpRequest.setAttribute(item.getFieldName(), item);
         }

         chain.doFilter(new 
            HttpServletRequestWrapper(httpRequest) {
               public Map<String, String[]> getParameterMap() {
                  return map;
               }                   
               // busywork follows ... should have been part of the wrapper
               public String[] getParameterValues(String name) {
                  Map<String, String[]> map = getParameterMap();
                  return (String[]) map.get(name);
               }
               public String getParameter(String name) {
                  String[] params = getParameterValues(name);
                  if (params == null) return null;
                  return params[0];
               }
               public Enumeration<String> getParameterNames() {
                  Map<String, String[]> map = getParameterMap();
                  return Collections.enumeration(map.keySet());
               }
            }, response);
      } catch (FileUploadException ex) {
         ServletException servletEx = new ServletException();
         servletEx.initCause(ex);
         throw servletEx;
      }      
   }   
}

5.Затем я прописал фильтр в web.xml.(Я хотел использовать аннотацию, но я не знал, как, знает ли кто -нибудь, как я могу это сделать с помощью аннотации?) Также добавил corejsf.taglib.xml

<!-- NEEDED FOR FILE UPLOAD -->
<filter>
      <filter-name>Upload Filter</filter-name>
      <filter-class>com.corejsf.UploadFilter</filter-class>
      <init-param>
         <param-name>sizeThreshold</param-name>
         <param-value>1024</param-value>
      </init-param>
</filter>

   <filter-mapping>
      <filter-name>Upload Filter</filter-name>
      <url-pattern>/faces/upload/*</url-pattern>
   </filter-mapping> 

    <context-param>
      <param-name>javax.faces.PROJECT_STAGE</param-name>
      <param-value>Development</param-value>
   </context-param>
   <context-param>
      <param-name>facelets.LIBRARIES</param-name>
      <param-value>/WEB-INF/corejsf.taglib.xml</param-value>
   </context-param>   

6. В моей папке WebContent я создал подпапку под названием «Загрузка» (Место назначения загруженных файлов).

enter image description here

7. Внутри страницы jsf я использую тег для загрузки и отправки, а также использую метод управляемого компонента для создания имен файлов:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:corejsf="http://corejsf.com">
            ....
    <h:form enctype="multipart/form-data">

     <corejsf:upload target="upload/#{placeAddController.prepareUniqueIdentifier}" />

         ....

        <h:commandButton value="Dalje" style=" font-weight: bold;  font-size:150%; action="/submittedImage" />  

    ...

    </h:form>

И управляемый Java-компонент:

@ManagedBean
@RequestScoped
public class PlaceAddControler {
…
public String prepareUniqueIdentifier() {
        return UUID.randomUUID().toString()+"png";
    }   

-Вроде все в порядке, но чего-то не хватает или что-то не так.Как думаете, почему не загружается?

Это было полезно?

Решение

Фильтр видимо не был активирован.Поместите точки останова отладки на doFilter() метод или добавьте операторы Logger или System.out.println() операторы, чтобы узнать, какой именно код выполняется, а какой нет, и какие именно переменные установлены.

Фильтр будет вызываться только тогда, когда URL-адрес запроса соответствует URL-адресу фильтра. <url-pattern>.Он должен соответствовать шаблону URL-адреса URL-адреса запроса, который вы видите в адресной строке браузера на странице JSF с формой загрузки.Поскольку вы настроили шаблон URL-адреса, /faces/upload/*, он будет вызван только тогда, когда URL-адрес запроса будет выглядеть примерно так

http://localhost:8080/имяконтекста/faces/upload/form.xhtml

Что касается вопроса о том, как аннотировать фильтр, используйте @WebFilter.

@WebFilter(urlPatterns={"/faces/upload/*"})
public class UploadFilter implements Filter {
    // ...
}

Несвязанный к проблеме, в коде есть некоторые недочеты (да, я знаю, большинство не ваше, просто хочу предупредить):

  1. Этот фильтр не поддерживает параметры запроса с несколькими значениями, например foo=val1&foo=val2&foo=val3 как вы можете получить, когда в формах используются множественный выбор или множественный флажок.Таким образом, только последнее выбранное/проверенное значение попадает в карту параметров.Я бы рекомендовал соответствующим образом исправить код фильтра.

  2. Хранение загруженных файлов в папке веб-контента бесполезно, если вам нужно постоянное хранилище.Всякий раз, когда вы повторно развертываете файл WAR/EAR веб-приложения, исходно развернутая папка веб-приложения будет полностью удален, включая файлы, которые были добавлены во время выполнения веб-приложения.Веб-сервер не сохраняет изменения в только что расширенной папке веб-приложения.Если вам нужно более постоянное хранилище, вам следует хранить файлы за пределами папки веб-приложения, желательно по абсолютному пути.Например. /var/webapp/upload.

Смотрите также:

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top