пятница, 4 декабря 2015 г.

Как сделать простую плановую рассылку, используя google sheets

1.Создать таблицу в google sheets
2.Заполнить столбцы : электронная почта(B) и текст(C)
3.Войти в редактор скриптов: Инструменты\Редактор скриптов
4.Код наподобие этого:
function sendEmails() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var startRow = 2;  // First row of data to process
  var numRows = 10;   // Number of rows to process
  // Fetch the range of cells A2:B3
  var dataRange = sheet.getRange(startRow, 1, numRows, 4)
  // Fetch values for each row in the Range.
  var data = dataRange.getValues();
  for (i in data) {
    var row = data[i];
    var name = row[0];  // First column
    var emailAddress = row[1];  // Second column
    if (emailAddress != '') {
      var message = 'Сообщение на русском языке: ' + row[1] + ' ::: ' + row[2] + ' ::: ' + row[3] ;//row[2];       // Третий столбец
      var subject = "Sending emails from a Spreadsheet";
      MailApp.sendEmail(emailAddress, subject, message);    
    };
  }
}
5.Настроить планировщик(триггер) регулярного запуска скрипта рассылки
  5.1.Инструменты\Редактор скриптов\Триггеры текущего проекта (кнопка с часами)
  5.2.Добавить триггер ("Триггеры не настроены.Нажмите здесь, чтобы добавить триггер")
    5.2.1 Выбрать нужную функцию (в нашем случае sendEmails), "динамичный", нужный таймер, регулярность
    5.2.2 Сохранить
    5.2.3 Дать разрешение(авторизацию) скрипту, которую он попросит при сохранении.

Это всё.

Примечания
Разумеется столбцы могут быть любые, а не только A и B - это отразится в индексах, в скрипте 

четверг, 5 ноября 2015 г.

Форматирование кода в блоге

Так как я не нашёл в "родных" средствах blogger, хоть какого-то форматирование кода, а некрасивый код вставлять надоело, то теперь использую простой до невозможности проект http://hilite.me/
Выбрал язык, вставил в левое окошко, нажал на кнопку, скопировал результат из окна. Короче, здесь копипаст рулит :)

Решение для "Unable to locate Spring NamespaceHandler for XML schema namespace"

Дано

Jar-файл, собранный с зависимыми библиотеками прямо внутри (это когда просят сделать весь проект в одном файле, и тогда сторонние библиотеки разжимаются и копируются в целевой jar в виде классов);
Конфигурация spring в xml-файлах, также внутри jar-а
Внешний проект запускает метод, в котором создаётся ApplicationContext spring-а.
Для сборки используется ant

Проблема

При попытке загрузить конфиг во внешнем проекта получаеv ошибку при создании ApplicationContext : "Unable to locate Spring NamespaceHandler for XML schema namespace"

Что дали поиски проблемы 
В двух словах, при сборке нескольких spring-библиотек в один файл, перекрываются схемы и другие настройки, которые хранятся в META-INF/spring.* файлах, которые для каждой библиотеки спринга свои. Т.е. остаются в итоге те, что собирались последними - они просто накрывают предыдущие.

Источники

http://stackoverflow.com/questions/8523997/unable-to-locate-spring-namespacehandler-for-xml-schema-namespace-http-www-sp/8574629#8574629
http://stackoverflow.com/questions/23574979/creating-an-uber-jar-with-spring-dependencies (это уже почти решение)

Решение (быстрое)

По мотивам описанного на stackoverflow был сделан отдельный ant-скрипт, который создаёт общие META-INF/spring.* схемы и настройки. Затем эти файлы были добавлены в папку с META-INF, которая подкладывается в финальный jar при сборке.
А в процессе сборки jar-а, исключаются те spring-настройки, которые разжимаются из spring-библиотек.

Скрипт ant, который собирает из отдельных spring-настроек, всё в общие настройки для всех библиотек spring-а, которые используются в проекте.

<?xml version="1.0" encoding="UTF-8"?>
<project name="springschemamake" default="create.spring.schema.full">

    <taskdef resource="net/sf/antcontrib/antlib.xml" classpath="lib/ant-contrib-1.0b3.jar"/>

    <property name="lib.dir" value="${basedir}/lib"/>
    <property name="dist.dir" value="${basedir}/templib"/>
    <target name="create.spring.schema.full">

        <!-- iterate over the dependencies -->
        <for param="file">
            <path>
                <fileset dir="${lib.dir}">
                    <include name="**/*spring*.jar"/>
                </fileset>
            </path>
            <sequential>

                <local name="jar.name"/>
                <basename  property="jar.name" file="@{file}"/>
                <!-- put the spring.* jars into special sub-directories -->
                <mkdir dir="${dist.dir}/${jar.name}"/>
                <unzip dest="${dist.dir}/${jar.name}" src="@{file}">
                    <patternset>
                        <include name="**/META-INF/spring.*"/>
                    </patternset>
                </unzip>

            </sequential>
        </for>

        <mkdir dir="${dist.dir}/META-INF"/>
        <!-- build the concatenated spring.* files -->
        <mkdir dir="${dist.dir}/META-INF"/>
        <concat destfile="${dist.dir}/META-INF/spring.handlers" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.handlers"/>
        </concat>
        <concat destfile="${dist.dir}/META-INF/spring.schemas" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.schemas"/>
        </concat>
        <concat destfile="${dist.dir}/META-INF/spring.tooling" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.tooling"/>
        </concat>
        <concat destfile="${dist.dir}/META-INF/spring.factories" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.factories"/>
        </concat>

        <delete includeemptydirs="true">
            <fileset dir="${dist.dir}" includes = "**/*spring*/**" excludes="/META-INF/**"/>
        </delete>
    </target>
</project>

Решение правильное, но пока не сделанное
Включить сборку схем spring-а в общий ant-скрипт. Он и до такого включения был довольно большой, поэтому потребуется некоторое время на рефакторинг и реализацию. 

среда, 16 сентября 2015 г.

Oracle. Как создать FK на поле из таблицы в другой схеме.

 По умолчанию, при попытке создать FK на поле из таблицы в другой схемы, получаем ошибку "недостаточно прав". Соответственно, надо добавить права приблизительно так:

GRANT REFERENCES ON <таблица из другой схемы> TO <пользователь, где таблица, в которой создаётся FK>;

Пример


-- добавляем разрешение
GRANT REFERENCES ON USER1.T15 TO USER2;

-- FK в таблице USER2.FK_TEST
alter table FK_TEST
  add constraint FK_F1 foreign key (F1)
  references USER1.T15(F1_ID);

Здесь,
таблица НА которую ссылается FK называется T15 и находится в пользователе USER1 (поле F1_ID),
а таблица, поле КОТОРОЙ ссылается на FK находится в пользователе USER2 и называется FK_TEST (поле с FK, соответственно F1)

Вот тут пример подробнее : http://www.akadia.com/services/ora_references_constraint.html

четверг, 12 марта 2015 г.

Перехват обращений к статическим ресурсам в Spring(3.2.2)


Дано

MVC-конфигурация с контроллерами и статическими ресурсами, которые не проходят через DispatcherServlet.

Требуется

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


Конфигурация

web.xml:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>testServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>testServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>


applicationContext.xml

    <!-- статические ресурсы (которые не должны проходить через DispatcherServlet) -->
    <mvc:resources mapping="/static/**" location="/static/"/>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/js/*"/>
            <bean class="ru.pevgen.test.RequestProcessingTimeInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

RequestProcessingTimeInterceptor.java

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class RequestProcessingTimeInterceptor extends HandlerInterceptorAdapter {
    private static final Logger logger = LoggerFactory.getLogger(RequestProcessingTimeInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        long startTime = System.currentTimeMillis();
        logger.info("Request URL::" + request.getRequestURL().toString()
                + ":: Start Time=" + System.currentTimeMillis());
        request.setAttribute("startTime", startTime);
        //if returned false, we need to make sure 'response' is sent
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("Request URL::" + request.getRequestURL().toString()
                + " Sent to Handler :: Current Time=" + System.currentTimeMillis());
        //we can add attributes in the modelAndView and use that in the view page
    }
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        long startTime = (Long) request.getAttribute("startTime");
        logger.info("Request URL::" + request.getRequestURL().toString()
                + ":: End Time=" + System.currentTimeMillis());
        logger.info("Request URL::" + request.getRequestURL().toString()
                + ":: Time Taken=" + (System.currentTimeMillis() - startTime));
    }
}

Пример честно содран отсюда: http://www.journaldev.com/2676/spring-mvc-interceptors-example-handlerinterceptor-and-handlerinterceptoradapter
Я использовал spring 3.2.2, на остальных не проверял