jsp: getProperty null, когда enctype = & ldquo; multipart / form-data & rdquo; атрибут используется

Я придумал другой подход, который мог бы преобразовать любой struct без хлопот фиксирующей длины, однако полученный массив байтов имел бы немного больше накладных расходов.

Вот пример struct:

[StructLayout(LayoutKind.Sequential)]
public class HelloWorld
{
    public MyEnum enumvalue;
    public string reqtimestamp;
    public string resptimestamp;
    public string message;
    public byte[] rawresp;
}

Как вы можете видеть, для всех этих структур потребуется добавить атрибуты фиксированной длины. Который часто мог занять больше места, чем требовалось. Обратите внимание, что требуется LayoutKind.Sequential, так как мы хотим, чтобы отражение всегда давало нам тот же порядок, когда тянул за FieldInfo. Мое вдохновение - от TLV Type-Length-Value. Давайте посмотрим на код:

public static byte[] StructToByteArray<T>(T obj)
{
    using (MemoryStream ms = new MemoryStream())
    {
        FieldInfo[] infos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach (FieldInfo info in infos)
        {
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream inms = new MemoryStream()) {

                bf.Serialize(inms, info.GetValue(obj));
                byte[] ba = inms.ToArray();
                // for length
                ms.Write(BitConverter.GetBytes(ba.Length), 0, sizeof(int));

                // for value
                ms.Write(ba, 0, ba.Length);
            }
        }

        return ms.ToArray();
    }
}

Вышеупомянутая функция просто использует BinaryFormatter для сериализации неизвестного размера raw object, и я просто отслеживаю размер и сохраняю его внутри выхода MemoryStream тоже.

public static void ByteArrayToStruct<T>(byte[] data, out T output)
{
    output = (T) Activator.CreateInstance(typeof(T), null);
    using (MemoryStream ms = new MemoryStream(data))
    {
        byte[] ba = null;
        FieldInfo[] infos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach (FieldInfo info in infos)
        {
            // for length
            ba = new byte[sizeof(int)];
            ms.Read(ba, 0, sizeof(int));

            // for value
            int sz = BitConverter.ToInt32(ba, 0);
            ba = new byte[sz];
            ms.Read(ba, 0, sz);

            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream inms = new MemoryStream(ba))
            {
                info.SetValue(output, bf.Deserialize(inms));
            }
        }
    }
}

Когда мы хотим преобразовать его обратно в исходное struct, мы просто прочтем длину и вернем его обратно в BinaryFormatter, который в свою очередь сбрасывает его обратно в struct .

Эти 2 функции являются общими и должны работать с любым struct, я протестировал вышеуказанный код в моем проекте C#, где у меня есть сервер и клиент, подключенный и обменивающийся через NamedPipeStream и я пересылаю свой struct в виде массива байтов от одного и к другому и преобразовываю его обратно.

Я считаю, что мой подход может быть лучше, поскольку он не фиксирует длину самого struct и единственные накладные расходы - это всего лишь int для каждого поля, которое у вас есть в вашей структуре. Внутри байтового массива, генерируемого BinaryFormatter, есть немного незначительных накладных расходов, но кроме этого, это немного.

0
задан Alice 10 March 2019 в 18:58
поделиться

1 ответ

Я выяснил, почему enctype="multipart/form-data" не работает с jsp:setProperty and jsp:getProperty. Поскольку я работаю с tomcat, process.jsp был сгенерирован как process_jsp.java.

  dao.User bean = null;
  bean = (dao.User) _jspx_page_context.getAttribute("bean", javax.servlet.jsp.PageContext.PAGE_SCOPE);
  if (bean == null){
    bean = new dao.User();
    _jspx_page_context.setAttribute("bean", bean, javax.servlet.jsp.PageContext.PAGE_SCOPE);
    out.write('\n');
    org.apache.jasper.runtime.JspRuntimeLibrary.introspect(_jspx_page_context.findAttribute("bean"), request);
    out.write(' ');
    out.write(' ');
    out.write('\n');
  }

В соответствии с вышеуказанным исходным кодом org.apache.jasper.runtime.JspRuntimeLibrary.introspect был назван.

   public static void introspect(Object bean, ServletRequest request) throws JasperException
    {
        Enumeration<String> e = request.getParameterNames();
        while ( e.hasMoreElements() ) {
            String name  = e.nextElement();
            String value = request.getParameter(name);
            introspecthelper(bean, name, value, request, name, true);
        }
    }

Над параметрами и именами запроса карты кода (именами свойств бинов) и затем introspecthelper будет передано значение в соответствующие методы установки с помощью java.lang.reflect.Method.invoke.

При работе с enctype="multipart/form-data" проблема заключается в Enumeration<String> e = request.getParameterNames(). Элемент не был найден, поэтому introspecthelper никогда не выполняется.

Потому что JspRuntimeLibrary.introspect является статическим методом. Я не могу отменить его поведение. Итак, написание пользовательского тега или следование Как загрузить файлы на сервер с помощью JSP / Servlet? - единственный способ решить эту проблему.

0
ответ дан Alice 10 March 2019 в 18:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: