четверг, 30 июля 2020 г.

СЭД: The parameter is incorrect.

Если во время входа в сервис СЭД вы видите страницу с ошибкой:

Ошибка в приложении!

Для перезапуска приложения перейдите по этой ссылке!

...

jcifs.smb.SmbException: The parameter is incorrect.

Сообщите о возникновении данной ошибки Администратору Системы.

Тогда вам поможет "gpedit.msc": Конфигурация компьютера → Конфигурация Windows → Параметры безопасности → Локальные политики → Параметры безопасности → "Сетевая безопасность: уровень проверки подлинности LAN Manager" = "Отправлять LM- и NTLM ответы".

суббота, 11 июля 2020 г.

Потокобезопасность. Начало.

Мое знакомство с многопоточностью.

Плохой пример:
public class PingServlet extends HttpServlet {
    private List OutputList = new ArrayList<>();
    private List OutputErrorList = new ArrayList<>();
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        OutputList.clear();
        OutputErrorList.clear();
        try {
            String ip = request.getParameter("ip");
            InetAddress host = InetAddress.getByName(ip);
            int ping_count = 4;
            int ping_timeout_seconds = 2;
            int ping_timeout_milliseconds = ping_timeout_seconds * 1000;
            int ping_ttl = 54;
            OutputList.add("Обмен " + ping_count + " пакетами с timeout " + ping_timeout_seconds + " сек. и TTL " + ping_ttl + ".");
            int i = 1;
            while (i <= ping_count) {                 if (host.isReachable(null, ping_ttl, ping_timeout_milliseconds)) {                     OutputList.add(ip + ": ОК.");                 } else {                     OutputList.add(ip + ": узел недоступен.");                 }                 i++;             }         } catch (Exception e) {             e.printStackTrace();             OutputErrorList.add(e.toString());         }         response.setContentType("text/html; charset=UTF-8"); // Для правильной обработки кириллицы.         if (request.getCharacterEncoding() == null) { // Без этого неправильно выполнялась обработка ввода с кирилицей.             request.setCharacterEncoding("UTF-8");         }         request.getSession().setAttribute("servlet_data_ping", OutputList);         request.getSession().setAttribute("servlet_error_ping", OutputErrorList);         request.getRequestDispatcher("ping.jsp").include(request, response);     } }

Внимание на эти строки:



При такой реализации одновременное выполнение в нескольких потоках приводит к смешиванию значений из нескольких потоков в одной переменной:


Один из вариантов исправления:
public class PingServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List OutputList = new ArrayList<>();
        List OutputErrorList = new ArrayList<>();
        try {
            String ip = request.getParameter("ip");
            InetAddress host = InetAddress.getByName(ip);
            int ping_count = 4;
            int ping_timeout_seconds = 2;
            int ping_timeout_milliseconds = ping_timeout_seconds * 1000;
            int ping_ttl = 54;
            OutputList.add("Обмен " + ping_count + " пакетами с timeout " + ping_timeout_seconds + " сек. и TTL " + ping_ttl + ".");
            int i = 1;
            while (i <= ping_count) {                 if (host.isReachable(null, ping_ttl, ping_timeout_milliseconds)) {                     OutputList.add(ip + ": ОК.");                 } else {                     OutputList.add(ip + ": узел недоступен.");                 }                 i++;             }         } catch (Exception e) {             e.printStackTrace();             OutputErrorList.add(e.toString());         }         response.setContentType("text/html; charset=UTF-8"); // Для правильной обработки кириллицы.         if (request.getCharacterEncoding() == null) { // Без этого неправильно выполнялась обработка ввода с кирилицей.             request.setCharacterEncoding("UTF-8");         }         request.getSession().setAttribute("servlet_data_ping", OutputList);         request.getSession().setAttribute("servlet_error_ping", OutputErrorList);         request.getRequestDispatcher("ping.jsp").include(request, response);     }     protected void doPost(HttpServletRequest request, HttpServletResponse response) {     } }


Внимание на эти строки:

четверг, 14 мая 2020 г.

Доступ к СУБД Firebird 3.0 через JSP под Tomcat

Пример доступа к БД Firebird 3.5 через JSP под Tomcat.

Чтобы научить Apache Tomcat 9 под Java 1.8 подключаться к базам Firebird 3.0, копируем из архива jaybird-4.0.0.java8.zip файлы jaybird-full-4.0.0.java8.jar, lib\antlr-runtime-4.7.2.jar, lib\connector-api-1.5.jar, lib\jna-5.5.0.jar в папку <tomcat>\lib.
Создаем web-приложение: JSP-страница, которая будет выводить содержимое таблицы "USER" из БД "c:/data/base.fdb" сервера "dbserver"
<tomcat>\webapps\test_app\index.jsp

Листинг index.jsp:
<%@page import="java.sql.*" %>
<%Class.forName("org.firebirdsql.jdbc.FBDriver"); %>
<HTML>
    <HEAD>
        <TITLE>Database access through JSP</TITLE>
    </HEAD>
    <BODY>
        <H1>Result of select query</H1>
        <%
            Connection connection = DriverManager.getConnection(
                "jdbc:firebirdsql:dbserver/3255:c:/data/base.fdb",
                "SYSDBA",
                "masterkey");
            Statement statement = connection.createStatement();
            ResultSet resultset = statement.executeQuery("select id, name from user order by id asc");
        %>
        <TABLE BORDER="1">
            <TR>
                <TH>id</TH>
                <TH>name</TH>
            </TR>
            <% while(resultset.next()){ %>
            <TR>
                <TD> <%= resultset.getString(1) %></TD>
                <TD> <%= resultset.getString(2) %></TD>
            </TR>
            <% } %>
        </TABLE>
    </BODY>
</HTML>

вторник, 18 февраля 2020 г.

Четверги

27.02.2020
12.03.2020
26.03.2020
09.04.2020
23.04.2020
07.05.2020
21.05.2020
04.06.2020
18.06.2020
02.07.2020
16.07.2020
30.07.2020
13.08.2020
27.08.2020
10.09.2020
24.09.2020
08.10.2020
22.10.2020
05.11.2020
19.11.2020
03.12.2020
17.12.2020
31.12.2020

суббота, 15 февраля 2020 г.

Исполняемый блок с перебором значений, указанных через запятую

declare
    dbnames varchar(32767) := 'DBNAME1, DBNAME2, DBNAME3';
    dbcnt integer;
    dbnames_length integer;
    separ_position integer := 0;
    dbname varchar(32767);
begin
/* Сразу убираем лишние символы (в этом примере - пробелы) */
    dbnames := replace(dbnames,' ','');
    dbnames_length := length(dbnames);
    dbcnt := regexp_count(dbnames, ',') + 1;
    for i in 1..dbcnt loop
        separ_position := instr(dbnames,',');
        dbname := substr(dbnames, 1, separ_position - 1);
/* Если итерация последняя, то берем остаток строки без вычислений */
        if i = dbcnt then dbname := dbnames; end if;
        dbms_output.put_line(dbname);
/* Отсекаем от начала исходной переменной "отработанную" часть */        
        dbnames := substr(dbnames, separ_position + 1,dbnames_length);
    end loop;    
end;

Исполняемый блок SQL с итерациями по ID

DECLARE
    c integer := 0;
    find_s varchar(15) := 'ORGACC_IDS="';
    accstr varchar(32767);
    ac_id integer;
    acc_num varchar2(35);
    tmp1_acc_cnt integer := 0;
    o_inn varchar2(20);
    o_name varchar2(255);
CURSOR crsr is
    select
    r.id,
    r.DOC_NUMBER,
    t.CAPTION,
    INSTR(r.PARAMS,find_s)+12 as START_TAG,
    INSTR(r.PARAMS,'"',INSTR(r.PARAMS,find_s)+12+1) as END_TAG,
    ((INSTR(r.PARAMS,'"',INSTR(r.PARAMS,find_s)+12+1))-(INSTR(r.PARAMS,find_s)+12)) as TAG_LEN,
    SUBSTR(r.PARAMS,INSTR(r.PARAMS,find_s)+12,((INSTR(r.PARAMS,'"',INSTR(r.PARAMS,find_s)+12+1))-(INSTR(r.PARAMS,find_s)+12))) as ACC_STR,
    regexp_count(SUBSTR(r.PARAMS,INSTR(r.PARAMS,find_s)+12,((INSTR(r.PARAMS,'"',INSTR(r.PARAMS,find_s)+12+1))-(INSTR(r.PARAMS,find_s)+12))),',')+1 as ACC_CNT
    from PBSREPTEMPLATE r join PBSREPTYPE t on t.id=r.PBSREPTYPE_ID
    /* where r.BUDGET_ID in () */ /* where r.id in (800000001851) - для проверки на одном шаблоне */;
BEGIN
    dbms_output.put_line('ID'||chr(09)||'Номер'||chr(09)||'Тип'||chr(09)||'Счет'||chr(09)||'ИНН'||chr(09)||'Организация');
    FOR s in crsr LOOP
        accstr := s.ACC_STR;
        FOR i in 1..s.ACC_CNT LOOP /* Разбираем строку с перечислением ID счетов на отдельные части */
            c := INSTR(accstr,',');
            ac_id := SUBSTR(accstr,1,c-1);
            accstr := SUBSTR(accstr,c+1,s.TAG_LEN);
            if i = s.ACC_CNT then ac_id := accstr; end if; /* Если итерация крайняя, то выводим остаток строки с перечислением ID счетов, там как раз остается крайний счет */
            select count(*) into tmp1_acc_cnt from orgaccount where close_date is null and id = ac_id;
            if tmp1_acc_cnt = 0 then continue; end if; /* Если счет закрыт, то вывод инфы пропускаем */
            select ACCOUNT_NUMBER into acc_num from orgaccount where close_date is null and id = ac_id;
            select o.taxcode, o.caption into o_inn, o_name from org o where exists (select null from orgaccount oa where oa.ORG_ID=o.id and oa.id = ac_id);
            dbms_output.put_line(s.id||chr(09)||trim(s.DOC_NUMBER)||chr(09)||s.CAPTION||chr(09)||acc_num||chr(09)||o_inn||chr(09)||o_name);
        END LOOP;
    END LOOP;
END;

Архив