Блог о программировании

Февраль 17, 2012

 

Другой способ защиты

На этой неделе друг со старой работы написал про свой способ защиты java проектов.
Около полугода назад я писал про то, как прятать строки в properties-файлах с помощью jasypt (EncryptableProperties и защита от дурака).
На самом деле, все понимают, что это всего-лишь защита от самого простого случая. Например, чтобы любопытный админ заглянув в файлик, не увидел там то, что не должен знать.
Тем не менее, если есть доступ к классам, то можно jad-ом отдекомпилировать исходники и получить доступ к "запретной" информации (например оригинальный пароль, которым шифруются properties разработчиком-оптимистом).

Для более серьезной защиты используют обфускаторы. Он усложняет работу по реверсу, но по большому счету распутывание логики это вопрос времени.

Так вот, российскими программистами сделан специальный продукт для защиты java-проектов.
Ключевое в нем - AES-шифровка строк. Кроме этого он делает динамические инъекции и использует специальные механизмы, которые мешают поломать приложение через рефлекшн.
Данное решение является коммерческим продуктом.

Подробнее здесь.

Блог о программировании

Февраль 7, 2012

 

Tomcat и jdbc connection pool

В общих чертах что такое пул.

Пул (pool) - это такой "бассейн" иди "резервуар" из которого можно брать "живые" объекты для дальнейшего их использования.
В данной статье будут рассматриваться только пулы подключений к БД, но в жизни программиста могут повстречаться пулы разных объектов, например многим знаком Thread Pool.
В общем случае, пул "каких-то объектов" - это шаблонный способ решения проблемы хранения и раздачи объектов (и самое главное поддержания их в нормально рабочем состоянии).

По аналогии с бассейном, в нормальных пулах постоянно протекают некоторые процессы. Например осуществляется проверка не "протухли" ли объекты. Нужно ли создать новые? Сколько времени объекты находятся в пуле? Во многих пулах есть своя "ватерлиния" (high water mark), которая указывает на максимальный "объем" пула.

В этой статье будет кратко описан JDBC Connection Pool.

Использование такого пула оправдано тем, что каждое подключение к БД это ресурсоёмкая операция. Поэтому более экономная стратегия это установить несколько подключений и следить за их состояниям, по мере необходимости добавлять новые.

Существует несколько реализаций пулов подключений к БД.

Можно даже сделать свою имплементацию. Это не сверхзадача. Опасность заключается в том, что если сделать чуть-чуть не аккуратно, то ваш бассейн начнет протекать или объекты будут "тухнуть".
Для серверного ПО это особо не приятно.
Тем не менее, в 90-ые годы многие java программисты писали свои connection pool.

Сейчас конечно можно взять готовый.

Сразу хотел сказать про тех, кого проблемы выбора пула не должны сильно волновать.

  • У вас нормальный Application Server. В этом случае у вас готовый, надежный промышленный пул "из коробки".
  • Вы используете СУБД Oracle. У вас реализация пула "из коробки" - в jar-ике с драйверами.

В обоих случаях, самое главное научиться всё правильно настраивать.

Если вы не можете себе позволить нормальный сервер (или оракл), то можно попробовать разобраться с решениям "для бедных".

Итак варианты:

DBCP

DataBase Connection Pool - этот пул очень долгое время приводится в примерах на сайте Apache Tomcat.
Это не самый лучший пул, т.к. может создать deadlock-и. На данный момент я бы не стал его рекомендовать для применения в реальных (продакшн) версиях.

C3P0


Название этого пула созвучно с именем робота золотистого цвета из звездных войн (в фильме этого робота создал молодой Дарт Вейдер, он же Анакин Скайоукер).
Краткое объяснение этому названию следующее: Connection Pool 3.0 -> СP30 -> C3P0. Подробности можно прочитать по ссылке.

Это действительно неплохой пул. Например, в какой-то момент создатели одного известного ORM-фреймворка стали приводить в своих примерах именно работу с с3p0 (и ругаться на dpcp).

Данный пул я использую в нескольких своих проектах. Иногда он выкидывает неприятное исключение при переразвертывании веб-приложения, но в штатном режиме работает вполне устойчиво.

Можно скачать с сайта (ссылка) или установить из maven-репозитория (groupId:c3p0, artifactId:c3p0).

Принцип настройки JNDI ресурсов в томкате думаю объяснять не нужно. Всё просто. Можно указать как глобальные ресурсы, а в веб-приложении указать ссылку, либо можно указать непосредственно в context.xml. Все зависит от того, где у вас хранятся библиотеки и какая у вас конфигурация сервера.

Пример настройки (MySQL):

<Resource auth="Container" description="DB Connection" driverClass="com.mysql.jdbc.Driver" user="user" password="password" jdbcUrl="jdbc:mysql://localhost:3306/databasename?useUnicode=yes&amp;characterEncoding=UTF-8" factory="org.apache.naming.factory.BeanFactory" type="com.mchange.v2.c3p0.ComboPooledDataSource" name="jdbc/db" maxPoolSize="10" minPoolSize="0" maxConnectionAge="100" acquireRetryAttempts="60" acquireIncrement="1" preferredTestQuery="SELECT 1" testConnectionOnCheckout="true" />

Важно! Установить пул особого ума не требует. Основная задача настроить так, чтобы он стабильно работал и выдерживал нагрузку.
Значение каждого параметры нужно прочитать в документации.

Некоторые важные детали:

  • Может оказаться, что JDBC URL есть амперсанд (&). Если настройка осуществляется через XML-файл, то & надо заквотить (вместо param1=value1&param2=value2, пишем param1=value1&amp;param2=value2).
  • preferredTestQuery - запрос который проверяет подключение к БД. Зависит от конкретной СУБД.
  • testConnectionOnCheckout - прожорлив, если можно то лучше не использовать.
  • maxPoolSize и minPoolSize - возможные максимальное и минимальное количество подключений в пуле.
  • acquireRetryAttempts - если СУБД не доступна, сколько раз пытаться подключится. Ставим в 0 если хотим, чтобы долбились до бесконечности.

Tomcat 7 JDBC Pool


В 7-ом Tomcat выпустили свой собственный пул. Подробнее можно прочитать на сайте.

<Resource name="jdbc/db" auth="Container" description="DB Connection" username="username" password="password" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/databasename?useUnicode=yes&amp;characterEncoding=UTF-8" maxActive="10" maxIdle="3" maxWait="100" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" type="javax.sql.DataSource" />

Некоторые важные детали:

  • Нужно быть внимательным с атрибутами. Например в с3p0 был атрибут user, здесь - username (driverClass - driverClassName, jdbcUrl - url). Поскольку реализация разная, поэтому и настройки отличаются!
  • Можно использовать и не в семерке. Из дополнительных зависимостей - tomcat-juli.jar.

Про Oracle


C Oracle все не просто. Как правило, Oracle используют серьезные организации, у которых должен быть штатный ДБА-шник. Самый правильное и разумное решение, чтобы тюнинг подключения к СУБД осуществлял как раз администратор баз данных.
Если у вас Oracle XE (бесплатная), то у вас может быть целый букет разного рода ошибок и сложностей связанных с локалью и настройкой.
Поскольку эта статья не про то, как настроить Oracle XE, а про пулы подключений, поэтому приведу примерную конфигурацию, которую использую для девелоперских целей.

<Resource auth="Container" factory="oracle.jdbc.pool.OracleDataSourceFactory" type="oracle.jdbc.pool.OracleDataSource" name="jdbc/db" user="scott" password="tiger" connectionCachingEnabled="true" url="jdbc:oracle:thin:@localhost:1521:XE" />
  • Важно! Это только для разработки. В продакшн такую настройку использовать не стоит. Проконсультируйтесь с вашим DBA! Это не шутка.
  • Еще раз внимательно с атрибутами. Отличаются от с3p0 и tomcat 7 jdbc pool
  • Это пример для Oracle 10-ка XE. Для других версий нужно читать документацию, но принцип тот же. Если собираетесь использовать нагугленные из интернета примеры, то обратите внимание на аттрибут factory. В интернете очень много ложных примеров.

Блог о программировании

Январь 6, 2012

 

Java Zip + русские буквы в названиях файлов

Баг №4244499

Этот баг был зарегистрирован еще в 1999г.
Проблема была не только с русскими файлами, а например с французскими (как в примере).
Корни довольно глубокие и существовали серьезные (надеюсь) причины, по которым эту ошибку долгое время не исправляли. В итоге, много-много лет в Java нельзя было сделать простыми штатными средствами zip-архив, который бы содержал файлы с именами не на латинице.

К сожалению, жизнь такова, что все это время некоторых java-программистов заставляли делать такие zip-архивы. Приходилось использовать например apache-вский commons-compress.

Использовать очень просто. Алгоритм буквально в два шага:
Шаг 1. Загружаем jar-ик (ссылка) или просто добавляем в pom.xml зависимость (если maven) :

<dependencies> .... <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version>1.3</version> </dependency> </dependencies>

Шаг 2. Используем:

import java.io.File; import java.io.FileInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import static org.apache.commons.compress.utils.IOUtils.copy; /* * ТОЛЬКО В ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЯХ! * Пример очень небрежный, в реальных задачах код нужно причесать! * Author: Vit */ public class Sample {   public static void main(String[] args) throws Exception { File srcDir = new File("c:/temp/dir"); // список файлов File[] files = srcDir.listFiles(); File zipFile = new File(srcDir, srcDir.getName() + ".zip"); // архив ZipArchiveOutputStream zaos = new ZipArchiveOutputStream(zipFile); for (File itemFile : files) { ZipArchiveEntry entry = new ZipArchiveEntry(itemFile.getName()); zaos.putArchiveEntry(entry); FileInputStream fis = new FileInputStream(itemFile); try { // копируем потоки copy(fis, zaos); } finally { fis.close(); } zaos.closeArchiveEntry(); } zaos.close(); } }

Счастливый конец.

В текущей версии JDK 7 этого бага уже нет.
Во-первых в семерке в ZIP API добавили новый конструктор, в котором можно явно указывать кодировку:
ZipOutputStream(OutputStream out,Charset charset)

Во-вторых, по-умолчанию используется стандартная UTF-8 кодировка.
Таким образом, дополнительных библиотек использовать не нужно, можно сразу делать zip-архив:

/* * ТОЛЬКО В ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЯХ! * Пример очень небрежный, в реальных задачах код нужно причесать! * Author: Vit */ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream;   public class Sample { public static void main(String[] args) throws Exception { File srcDir = new File("c:/temp/dir"); File[] files = srcDir.listFiles(); File zipFile = new File(srcDir, srcDir.getName() + "_j7.zip"); FileOutputStream fos = new FileOutputStream(zipFile);   try (ZipOutputStream zos = new ZipOutputStream(fos)) { for (File itemFile : files) { ZipEntry entry = new ZipEntry(itemFile.getName()); zos.putNextEntry(entry);   try (FileInputStream fis = new FileInputStream(itemFile)) { byte[] buff = new byte[8192]; int length = -1; while (-1 != (length = fis.read(buff))) { zos.write(buff, 0, length); } } zos.closeEntry(); } } } }

Блог о программировании

Декабрь 30, 2011

 

Работа с Maven + Tomcat

Maven и Tomcat


Ни для кого не секрет, что maven-ом можно деплоить проекты в Apache Tomcat.
Правда многие разработчики все-таки используют функции, встроенные в среду разработки (в Netbeans - из коробки, в Eclipse - ставим плагин).
Это удобно и просто, но к сожалению, мне приходится часто "перескакивать" с разных IDE и поэтому в некоторых своих проектах я предпочитаю сразу настроить tomcat:deploy.

На данный момент использую "tomcat-maven-plugin".

Запуск осуществляется командой: mvn tomcat:deploy.

Для удобство можно указать в IDE, чтобы эта команда выполнялась на действие "Run" или повесить на нее какой-нибудь HotKey.

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

В случае, если мы работаем в простых условиях, когда у нас имеется свой apache tomcat-ом установленный на локальном компьютере, то настройка довольно простая.
Нам нужно три файла.

  • tomcat-users.xml
  • settings.xml
  • pom.xml
  • tomcat-users.xml

    Файл, как правило, находится рядом с другими файлами для настройки сервера: APACHE_TOMCAT_DIR/conf/tomcat-users.xml

    В нем нужно проверить, что создана роль "manager" и существует пользователь с этой ролью.
    Что-то вроде этого:

    <tomcat-users> <role rolename="manager"/> <user username="user" password="123456" roles="manager"/> </tomcat-users>

    Таким образом, apache tomcat будет знать, что пользователю "user" можно развертывать у него war-ики.

    settings.xml

    Maven-овский файл с настройками. Есть глобальный файл на систему, есть под каждого пользователя.

    Я меняю как правило свой, пользовательский, он находится здесь:
    ${user.home}/.m2/settings.xml

    Если в Windows, то это будет файл "C:\Documents and Settings\имя_пользователя\.m2\settings.xml"

    В нем нужно указать Maven-у с каким логином и паролем нужно обращаться на сервер, чтобы запустить приложение.

    <?xml version="1.0" encoding="UTF-8"?> <settings> <servers> <server> <!-- id это просто идентификатор, используете удобное для вас название! Я называю так, чтобы не запутаться, т.к. у меня есть еще сервера других версий и других целей. --> <id>apache-tomcat-6.0.32</id> <!-- имя пользователя, которое вы указали в tomcat-users.xml --> <username>user</username> <!-- ну и естественно его пароль из tomcat-users.xml --> <password>123456</password> </server> </servers> </settings> </xml>

    pom.xml

    Теперь в pom.xml указываем настройки для деплойщика: project/build/plugins/plugin tomcat-maven-plugin

    <project> ... <build> ... <plugins> ... <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>tomcat-maven-plugin</artifactId> <configuration> <!-- id-шник из settings.xml --> <server>apache-tomcat-6.0.32</server> <url>http://localhost:8080/manager</url> <path>/mywebapp</path> </configuration> </plugin> ... </plugins> ... </build> ... </project>

    Таким образом в pom.xml указывается только id сервера. Этот способ хорош тем, что вы не показываете в этом файле свой логин и пароль от личного tomcat-а. Это важно поскольку pom.xml часто бывает общественным файлом (т.к. хранят его в репозиториях вместе с исходниками).

    Если резюмировать, то в целом все довольно просто. Нужно показать tomcat-у кому можно деплоить (tomcat-users.xml), показать maven-у к какому серверу и с каким логином и паролем стучаться (settings.xml) и настроить файл проекта, чтобы maven знал на какой конкретно сервер разворачивать (pom.xml).

    Блог о программировании

    Август 6, 2011

     

    UML в Javadoc через maven+umlgraph

    Где-то год назад писал про различные UML-редакторы.
    К сожалению, ситуация толком не изменилась, пока действительно удобного на 100% для себя инструмента для создания UML-диаграмм не нашел.
    UMLet - хорошо спасает в 80% случаев для быстрого прототипирования, но иногда его не хватает.

    Сейчас речь пойдет не о нем, а о UMLGraph.
    Это инструмент, который позволяет осуществлять декларативный способ рисования uml-диаграмм. Другими словами UML диаграммы создаются в текстовом виде, а не рисуется мышкой. Некоторым программистам (в частности мне) работать с текстом несколько удобней, чем с мышкой и со множеством графических объектов.

    Возможностей у UMLGraph довольно много, но лично меня интересовали только следующие его возможности:

    1. Рисование только диаграмм классов. Использование umlgraph для создания диаграмм последовательности, развертывания и т.д. мне не интересно.
    2. Встраивание полученных диаграмм в JavaDoc.
    3. Связка с maven-ом.

    В результате некоторых манипуляций, можно получить следующий результат:

    Что нужно для этого сделать:
    1. Необходимо установить Graphiz. Это утилита для рисования различных диаграмм, через нее будем создавать итоговые рисунки.

    Если у вас Windows, то для этого нужно:
    - Зайти на сайт http://www.graphviz.org/.
    - Выбрать пункт Download.
    - Прочитать лицензию, если все ОК - нажать "Agreе".
    - Выбрать дистрибутив под Windows и установить.

    Если у вас например Ubuntu, то все намного проще! Поскольку graphviz есть в стандартных репах, то вы можете установить через apt:

    sudo apt-get install graphviz

    2. Прописать в pom.xml использование umlgraph

    <project ...> ... <reporting> <plugins> <plugin> <artifactId>maven-javadoc-plugin</artifactId> <configuration> <doclet>org.umlgraph.doclet.UmlGraphDoc</doclet> <docletArtifact> <groupId>org.umlgraph</groupId> <artifactId>doclet</artifactId> <version>5.1</version> </docletArtifact> <additionalparam>-views -inferrel -inferdep -quiet -hide java.* -collpackages java.util.* -qualify -postfixpackage -attributes -operations -types -nodefontclassname "Arial" -nodefontclassabstractname "Arial Italic" -nodefontclasssize 10 -nodefontname "Arial" -nodefontabstractname "Arial Italic" -nodefontsize 10 -nodefonttagname "Arial Italic" -nodefonttagsize 10 -nodefontpackagename "Arial Italic" -nodefontpackagesize 10 -edgefontsize 10 </additionalparam> <useStandardDocletOptions>true</useStandardDocletOptions> </configuration> </plugin> </plugins> </reporting> ... </project>

    В additionalparam можно указать свои настройки, чтобы настроить отображение диаграмм на свой вкус и цвет. В этом примере я немного поигрался с шрифтами. Список возможных настроек можно посмотреть здесь: http://www.umlgraph.org/doc/cd-opt.html.

    3. Проверить, что программы из Graphiz установлены и доступен. Например можно набрать для этого в командной строке:

    dot --help

    4. Запустить mvn site. Как обычно в папке target появится директория с документацией.

    Выкладываю в для наглядности maven-овский проект umldemo.zip и
    полученную в итоге документацию umldemo-apidoc.zip.

    Пару полезных заметок:
    1. Чтобы исключить класс из диаграммы можно использовать опцию @hidden (см. пример PostA.java)
    2. Список возможных опций можно посмотреть здесь: http://www.umlgraph.org/doc/cd-model.html

    Блог о программировании

    Июль 24, 2011

     

    Выложил на GitHub число прописью

    Выложил под GPL-лицензией свою версию на Java число прописью.
    Это например когда из BigDecimal("777.77") надо сделать "Семьсот семьдесят семь рублей 77 копеек".
    В прошлом несколько раз искал такую штуку для разных проектов, а нормальной свободной реализации не было.
    Поскольку я сейчас являются независимым разработчиком и не связан никакими обязательствами,
    выкладываю свою версию под GPL.

    Версия сырая, многое нужно оптимизировать, буду рад любой помощи в добавлении новых языков.
    Сейчас есть только английский и русский.

    Ссылка на github: numerals.

    Блог о программировании

    Июль 21, 2011

     

    Firefox и localhost

    Недавно помогал ребятам из одной конторы (нужно было сделать на HTML5 Canvas графический редактор для их легаси-системы). Среди прочих задачек, была интересная проблемка с Firefox-ом - медленно обрабатывались запросы (1 запрос > 1 секунды).
    Так как веб-сервер - самописный (полностью!), то были подозрения на все-что угодно (ошибки в реализации протокола, проблемы в клиентском коде на javascript и т.д.).

    В итоге все-таки я проблему решил, оказалось очень забавно. Пишу здесь, может кому пригодится.
    Сервер тестировался на localhost-е, а в Firefox-е есть проблема http://goo.gl/jJc7g
    В общем проблема заключалась в медленном DNS-ресолве для localhost в Firefox-e (например 127.0.0.1 - не глючил)

    Самое просто решение (но не самое правильно):
    about:config -> network.dns.disableIPv6=true

    Подробнее о причинах и правильных решениях: http://kb.mozillazine.org/Network.dns.disableIPv6

    Блог о программировании

    Июль 19, 2011

     

    Мои хинты для Netbeans 7

    Недавно нужно было заново установить Netbeans 7.
    Вот некоторые действия, которые всегда приходится делать после установки "коробочной" версии,
    а именно: поддержка Scala, интерфейс на английском и quick file chooser.

    Установка

    Заходим на официальный сайт: netbeans.org
    Нажимаем на [Download FREE] и переходим на ссылку http://netbeans.org/downloads/index.html
    Скачиваем, устанавливаем и запускаем.

    Итак, что приходится делать:

    0. Обновления.

    На всякий случай проверить наличие обновлений:
    Меню → Help → Check for Updates

    1. Русский → English

    Чтобы вернуть обратно английский нужно:
    - Найти файл "netbeans.conf" (для Windows-пользователей: он должен находится где-то здесь - "C:\Program Files\NetBeans 7.0\etc\" )
    - Указать в настройках --locale en_US

    netbeans_default_options="МНОГО_БУКВ --locale en_US"

    2. File Chooser

    Сразу же установить плагин Quick File Chooser:
    Меню → Тools → Plugins → Available Plugins
    Это намного более шустрый и удобный (на мой взгляд) диалог для выбора файлов.

    3. Scala

    Ставим plugin для работы со Scala.
    Для версии 2.8.x: http://plugins.netbeans.org/plugin/36598/nbscala-2-8-x
    Подробнее можно прочитать на вики нетбинсов:
    http://wiki.netbeans.org/Scala
    или на портале с плагинами:
    http://plugins.netbeans.org/

    Блог о программировании

    Июль 4, 2011

     

    EncryptableProperties и защита от дурака

    Все знают, что не следует хранить в конфигурационных файлах (например properties) критически важную информацию в открытом виде.
    Например логины и пароли от базы данных, почты и т.д.
    Не стоит этого делать, т.к. "случайный" сисадмин или пользователь сможет открыть этот ваш файлик и увидеть пароль.

    С учетом того, что довольно часто пароли придумывают люди, то запомнить их бывает очень просто.
    Более того, некоторые пароли настолько поражают воображение, что их очень сложно забыть. Как правило они выглядят так: 123456, sa, manager и т.д...
    Конечно это личное дело каждого, но выставлять на обозрения такие свои пароли, как-то не совсем прилично.

    Если все-таки нет желания сильно напрягаться и прятать пароли в действительно укромные места, можно довольно просто сделать "защиту от дурака" (чтобы пароль явно не читался).

    Как вариант можно использовать Jasypt. Этот довольно большой проект и его можно использовать и в других целей, но мы будем разбирать простой и конкретный случай: предотвратить хранение паролей в открытом виде в properties файле.
    Главное, что нужно понимать, мы не строим защиту от серьезного злобного хакера, а делаем простую защиту от дурака!

    Для этого:
    Прописываем в pom.xml зависимость:

    <dependency> <groupId>org.jasypt</groupId> <artifactId>jasypt</artifactId> <version>1.7.1</version> </dependency>

    Если не maven, то можно просто скачать и подключить библиотеку с сайта. В любом случае, Jasypt удобен тем, что дополнительные зависимости не тянутся. Конечно, если нужна серьезная криптография, нужно будет кое-что доставить, но в нашем простом случае она нам не нужна. Мы просто хотим сделать так, чтобы пароль не смогли "тупо прочитать".

    Дальше читаем учебник: http://www.jasypt.org/encrypting-configuration.html

    Для того, чтобы спрятать пароль, можно воспользоваться утилитой командой строки. Идет вместе с дистрибутивом Jasypt. Находится в директории bin.
    Например:

    jasypt-1.7.1\bin>encrypt.bat input=manager password=trololo ... ----OUTPUT---------------------- R+1ZbGFUdbNYXLJHdqgzVw== ...

    Зашифрованное значение свойства, которое нужно спрятать оборачивается в ENC(). Пример:

    # Допустим сохраняем в файл /tmp/a.properties username=system password=ENC(R+1ZbGFUdbNYXLJHdqgzVw==)

    Теперь чтобы получить содержимое, воспользуемся примером из учебника:

    import java.util.Properties; import java.io.FileInputStream; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.properties.EncryptableProperties; public class PropApp { public static void main(String[] args) throws Exception { StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); // выставляем пароль для всего нашего EncryptableProperties: trololo encryptor.setPassword("trololo"); Properties props = new EncryptableProperties(encryptor); props.load(new FileInputStream("/tmp/a.properties")); // логин не замаскирован String datasourceUsername = props.getProperty("username"); // system System.err.println("datasourceUsername = " + datasourceUsername); // пароль будет расшифрован на лету String datasourcePassword = props.getProperty("password"); // manager System.err.println("datasourcePassword = " + datasourcePassword); } }

    Важно:

    • Легко видеть, что jasypt-овый EncryptableProperties является наследником обычного Properties. Таким образом, вы можете обращаться с ним как с обычным Properties.
    • EncryptableProperties меняет только метод getPropertу(), но не метод get(), который достался от Hashtable. Например, если в приведенном выше примере, вы вызовите метод props.get("password"), то получите ENC(R+1ZbGFUdbNYXLJHdqgzVw==)

    Блог о программировании

    Май 18, 2011

     

    Java + Excel файлы (Apache POI)


    С периодичностью раз в два-три года сталкиваюсь с проектами, в которых опять нужно работать с Excel файлами.
    Наверно это у меня что-то кармическое...
    Сейчас, в очередной раз приходиться реализовать полуавтоматический разбор сотен excel-файлов с прайсами.
    В прошлых своих проектах использовал JExcelApi.
    Ничего плохого про эту библиотеку сказать не могу, но хочется какого-то разнообразия в жизни поэтому в этот раз с товарищем решили попробовать Apache POI.

    Apache POI поддерживает как формат для обычных *.xsl файлов (HSSF) так и *.xslx файлы (XSSF).

    Кстати, формат для *.xsl файлы в Apache POI они обзывают "HSSF - Horrible SpreadSheet Format", то есть "Вселяющий ужас формат для электронных таблиц".
    Для того, чтобы приступить к работе, как обычно прописываем зависимости в pom.xml:

    <dependencies> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <!-- версия 3.7 - стабильная, 3.8 в "beta 2" (на 18 мая 2011г). --> <version>3.7</version> </dependency> </dependencies>

    Для примера, приведу очень простой файл - список ФИО, сумма + Итог:

    Если нужно просто вытащить текст, можно использовать "класс-извелкатель": ExcelExtractor

      import java.io.FileInputStream; import java.io.InputStream; import java.util.Iterator; import org.apache.poi.hssf.extractor.ExcelExtractor; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;   public class App {   public static void main(String[] args) throws Exception { InputStream in = new FileInputStream("/tmp/1.xls"); // Внимание InputStream будет закрыт // Если нужно не закрывающий см. JavaDoc по POIFSFileSystem : http://goo.gl/1Auu7 HSSFWorkbook wb = new HSSFWorkbook(in);   ExcelExtractor extractor = new ExcelExtractor(wb); extractor.setFormulasNotResults(false); // Считать формулы extractor.setIncludeSheetNames(true); String text = extractor.getText();   System.out.println(text);   } }

    Вывод на консоль:

    Sheet1 &A Смирнов 40000.0 Иванов 40000.0 Кузнецов 50000.0 Попов 40000.0 Соколов 70000.0 Лебедев 70000.0 Козлов 50000.0 Новиков 50000.0 Морозов 50000.0 Петров 40000.0 Итого 500000.0 Page &P Sheet2 &A Page &P Sheet3 &A Page &P

    Когда этого не достаточно (например нужно найти нужную ячейку и т.д.), без проблем можно использовать нормальное API:
    Пример:

    import java.io.FileInputStream; import java.io.InputStream; import java.util.Iterator; import org.apache.poi.hssf.extractor.ExcelExtractor; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*;   public class App {   public static void main(String[] args) throws Exception { InputStream in = new FileInputStream("/tmp/1.xls"); HSSFWorkbook wb = new HSSFWorkbook(in);   Sheet sheet = wb.getSheetAt(0); Iterator<Row> it = sheet.iterator(); while (it.hasNext()) { Row row = it.next(); Iterator<Cell> cells = row.iterator(); while (cells.hasNext()) { Cell cell = cells.next(); int cellType = cell.getCellType(); switch (cellType) { case Cell.CELL_TYPE_STRING: System.out.print(cell.getStringCellValue() + "="); break; case Cell.CELL_TYPE_NUMERIC: System.out.print("[" + cell.getNumericCellValue() + "]"); break;   case Cell.CELL_TYPE_FORMULA: System.out.print("[" + cell.getNumericCellValue() + "]"); break; default: System.out.print("|"); break; } } System.out.println(); } } }

    Вывод на консоль:

    Смирнов=[40000.0] Иванов=[40000.0] Кузнецов=[50000.0] Попов=[40000.0] Соколов=[70000.0] Лебедев=[70000.0] Козлов=[50000.0] Новиков=[50000.0] Морозов=[50000.0] Петров=[40000.0] Итого=[500000.0]

    Конечно если у вас не такие "рафинированные" примеры, то код будет намного более сложным.
    Скорее всего вам придется делать еще один уровень API, заточенный под ваши нужды или ваши файлы.
    Например у меня товарищ сделал для этих целей: Парсер на Scala поверх Apache POI для разбора Excel-файлов.

     
    << < 1 из 2 > >>