logo

11 июн. 2010 г.

BIP: отчеты с длинными именами в кириллице

Если вы делаете отчеты в BI Publisher и при этом используете кириллические названия, то, наверняка, сталкивались со следующей ошибкой при выгрузке отчета в Excel:




Ошибка «Возникла ошибка DDE …» возникает из-за ограничения MS Excel на общую длину открываемого файла (не больше 223 символов вместе с путем).
«Но ведь мой отчет имеет совсем коротенькое имя – всего лишь «супер-пупер…» - скажете вы.
Посмотрим HTTP-сниффером, во что превращается это коротенькое имя:



По 6 символов на каждую букву кириллицы. Понятно, что мы легко «вылезаем» из ограничения.

Предлагаю возможный выход из ситуации.
Для этого создадим новый класс-фильтр:

package oracle.apps.xdo.servlet;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

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.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class XxCyrillicFilter implements Filter {
protected FilterConfig config;

public void init(FilterConfig config) throws ServletException {
this.config = config;
}

public void destroy() {
}

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

if (request instanceof HttpServletRequest) {
newResponse = new XxResponseWrapper((HttpServletResponse) response);
}


chain.doFilter(request, newResponse);

}
}

class XxResponseWrapper extends HttpServletResponseWrapper
{

private String cyr = new String("\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u044B\u0439\u043A\u043B\u043C\u043D\u043E\u043F\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044C\u044D\u044E\u044F");
private String [] lat = {"a","b","v","g","d","e","yo","g","z","i","y","i",
"k","l","m","n","o","p","r","s","t","u",
"f","h","tz","ch","sh","sh","'","e","yu","ya"};

public String translitIt(String str)
{
str = str.toLowerCase();

StringBuffer newStr = new StringBuffer("");
char [] chs = str.toCharArray();

for (int i = 0; i < chs.length; i++)
{
int k = cyr.indexOf(chs[i]);

if (k != -1) newStr.append(lat[k]);
else newStr.append(chs[i]);
}

return newStr.toString();
}

public XxResponseWrapper(HttpServletResponse response)
{
super(response);
}

public void setHeader(String name, String value)
{
if (!"content-disposition".equalsIgnoreCase(name))
super.setHeader(name, value);

else
{
String changedCD = value;

if (value != null && value.length() > 150)
{
try {changedCD = this.translitIt(URLDecoder.decode(value, "UTF8"));}
catch (UnsupportedEncodingException e) {}
}

super.setHeader("content-disposition", changedCD);
}
}
}


Поместим его в доступное для контейнера сервлетов место:



(ссылка на архив с скомпилированными классами)

Изменим дескриптор развертывания веб-приложения xmlpserver



Добавим в него несколько строк:

XxCyrillicFilter
oracle.apps.xdo.servlet.XxCyrillicFilter



XxCyrillicFilter
/servlet/xdo


XxCyrillicFilter
*.xdo



Рестартуем OC4J. Видим, что теперь длинные имена отчетов в кириллице преобразуются в транслит:




П.С. Возможно, пока эта проблема не особенно актуальна для русских пользователей, использующих BIPublisher. Так как мало кто использует выгрузку (кнопка «Export») и затем сразу открывает файл. Обычно выгружают и сохраняют на локальный диск (уже в кодировке системы) – тем самым проблема не проявляется.
Но скоро мы поголовно будем использовать новую возможность, которую анонсировал Tim Dexter – создание отчетов с Excel-шаблонами, позволяющую использовать практически все native-свойства Excel. А в случае нажатия кнопки «View» отчета, созданного с использованием Excel-шаблона (а не как нам привычно - RTF), описанная проблема проявится.

1 комментарий:

  1. Приведенное решение тестировал только в IE. Оказалось, что в FF оно лишнее.
    Поправил класс:
    ...
    if (request instanceof HttpServletRequest) {
    String uAgent = ((HttpServletRequest)request).getHeader( "User-Agent" );
    boolean isMSIE = ( uAgent != null && uAgent.indexOf( "MSIE" ) != -1 );
    if (isMSIE)
    newResponse = new XxResponseWrapper((HttpServletResponse) response);
    }
    ...

    Ссылка на архив с классами и исходником:
    http://sites.google.com/site/obi2ru/oracle_classes_v2.rar?attredirects=0&d=1

    ОтветитьУдалить