Метки услуг
Материал из BiTel WiKi
(Удалено содержимое страницы) |
(Отмена правки 3309 участника Cromeshnic (обсуждение)) |
||
Строка 1: | Строка 1: | ||
+ | = Описание = | ||
+ | Для отчётов полезно иметь группировку услуг по типам вне зависимости от модуля. | ||
+ | Например, группа услуг "Интернет" - туда могут входить как услуги трафиков модулей Inet, Dialup, IPN, так и абонплаты за интернет. | ||
+ | Аналогично, "VPN" | ||
+ | Было решено сделать группировку аналогично меткам тарифов - в виде дерева меток. | ||
+ | |||
+ | Решение состоит из серверного API и клиентского интерфейса. | ||
+ | Решение является упрощённой копипастой работы с метками тарифов. | ||
+ | |||
+ | = Общие классы = | ||
+ | Классы, которые должны быть как в серверных библиотеках, так и в клиентских | ||
+ | |||
+ | Во-первых, нам понадобится веб-сервис для работы с метками тарифов: | ||
+ | |||
+ | <source lang="java"> | ||
+ | package ru.bitel.bgbilling.kernel.module.common.service; | ||
+ | |||
+ | import ru.bitel.bgbilling.common.BGException; | ||
+ | import ru.dsi.bgbilling.kernel.module.common.bean.ServiceItem; | ||
+ | import ru.dsi.bgbilling.kernel.module.common.bean.ServiceLabelItem; | ||
+ | |||
+ | import javax.jws.WebMethod; | ||
+ | import javax.jws.WebParam; | ||
+ | import javax.jws.WebService; | ||
+ | import java.util.List; | ||
+ | import java.util.Set; | ||
+ | |||
+ | @WebService | ||
+ | public abstract interface ServiceLabelService | ||
+ | { | ||
+ | @WebMethod | ||
+ | public abstract List<ServiceLabelItem> getServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId) | ||
+ | throws BGException; | ||
+ | |||
+ | @WebMethod | ||
+ | public abstract void setServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId, @WebParam(name="items") List<ServiceLabelItem> items) | ||
+ | throws BGException; | ||
+ | |||
+ | @WebMethod | ||
+ | public abstract int updateServiceLabelTreeItem(@WebParam(name="serviceLabelItem") ServiceLabelItem serviceLabelItem) | ||
+ | throws BGException; | ||
+ | |||
+ | @WebMethod | ||
+ | public abstract void removeServiceLabelTreeItem(@WebParam(name="serviceLabelItemId") int serviceLabelItemId) | ||
+ | throws BGException; | ||
+ | |||
+ | @WebMethod | ||
+ | public abstract List<ServiceItem> getServiceList(@WebParam(name="moduleIds") Set<Integer> moduleIds, | ||
+ | @WebParam(name="serviceLabelIds") List<Integer> serviceLabelIds) | ||
+ | throws BGException; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Элемент списка услуг для отображения: | ||
+ | |||
+ | <source lang="java"> | ||
+ | package ru.dsi.bgbilling.kernel.module.common.bean; | ||
+ | |||
+ | import ru.bitel.common.model.IdTitle; | ||
+ | |||
+ | import javax.xml.bind.annotation.XmlAttribute; | ||
+ | |||
+ | /** | ||
+ | * Услуга, расширенная доп информацией | ||
+ | */ | ||
+ | public class ServiceItem extends IdTitle{ | ||
+ | private int labelCount; | ||
+ | private String moduleTitle; | ||
+ | private int moduleId; | ||
+ | private boolean using; | ||
+ | |||
+ | @XmlAttribute | ||
+ | public int getLabelCount() { | ||
+ | return labelCount; | ||
+ | } | ||
+ | |||
+ | public void setLabelCount(int labelCount) { | ||
+ | this.labelCount = labelCount; | ||
+ | } | ||
+ | |||
+ | @XmlAttribute | ||
+ | public String getModuleTitle() { | ||
+ | return moduleTitle; | ||
+ | } | ||
+ | |||
+ | public void setModuleTitle(String moduleTitle) { | ||
+ | this.moduleTitle = moduleTitle; | ||
+ | } | ||
+ | |||
+ | @XmlAttribute | ||
+ | public int getModuleId() | ||
+ | { | ||
+ | return this.moduleId; | ||
+ | } | ||
+ | |||
+ | public void setModuleId(int moduleId) | ||
+ | { | ||
+ | this.moduleId = moduleId; | ||
+ | } | ||
+ | |||
+ | @XmlAttribute | ||
+ | public boolean isUsing() | ||
+ | { | ||
+ | return this.using; | ||
+ | } | ||
+ | |||
+ | public void setUsing(boolean used) | ||
+ | { | ||
+ | this.using = used; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Элемент дерева меток: | ||
+ | <source lang="java"> | ||
+ | package ru.dsi.bgbilling.kernel.module.common.bean; | ||
+ | |||
+ | import ru.bitel.common.model.IdTitle; | ||
+ | |||
+ | import javax.xml.bind.annotation.XmlAttribute; | ||
+ | |||
+ | public class ServiceLabelItem extends IdTitle | ||
+ | { | ||
+ | private int parentId = -1; | ||
+ | private int serviceLinkCount = 0; | ||
+ | private boolean selected = false; | ||
+ | |||
+ | @XmlAttribute | ||
+ | public int getParentId() | ||
+ | { | ||
+ | return this.parentId; | ||
+ | } | ||
+ | |||
+ | public void setParentId(int parentId) | ||
+ | { | ||
+ | this.parentId = parentId; | ||
+ | } | ||
+ | |||
+ | @XmlAttribute | ||
+ | public int getServiceLinkCount() | ||
+ | { | ||
+ | return this.serviceLinkCount; | ||
+ | } | ||
+ | |||
+ | public void setServiceLinkCount(int serviceLinkCount) | ||
+ | { | ||
+ | this.serviceLinkCount = serviceLinkCount; | ||
+ | } | ||
+ | |||
+ | @XmlAttribute | ||
+ | public boolean isSelected() | ||
+ | { | ||
+ | return this.selected; | ||
+ | } | ||
+ | |||
+ | public void setSelected(boolean selected) | ||
+ | { | ||
+ | this.selected = selected; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Renderer дерева меток: | ||
+ | |||
+ | <source lang="java"> | ||
+ | package ru.dsi.bgbilling.kernel.module.common.bean; | ||
+ | |||
+ | import ru.bitel.bgbilling.client.util.ClientUtils; | ||
+ | |||
+ | import javax.swing.*; | ||
+ | import javax.swing.tree.DefaultMutableTreeNode; | ||
+ | import javax.swing.tree.DefaultTreeCellRenderer; | ||
+ | import javax.swing.tree.TreeCellRenderer; | ||
+ | import java.awt.*; | ||
+ | |||
+ | public class ServiceLabelTreeCellRenderer extends JPanel | ||
+ | implements TreeCellRenderer | ||
+ | { | ||
+ | private JCheckBox check; | ||
+ | private DefaultTreeCellRenderer label; | ||
+ | |||
+ | public ServiceLabelTreeCellRenderer() | ||
+ | { | ||
+ | setLayout(new GridBagLayout()); | ||
+ | add(this.check = new JCheckBox(), new GridBagConstraints(0, 0, 1, 1, 0.0D, 0.0D, 17, 0, new Insets(0, 0, 0, 0), 0, 0)); | ||
+ | add(this.label = new DefaultTreeCellRenderer(), new GridBagConstraints(1, 0, 1, 1, 0.0D, 0.0D, 17, 0, new Insets(0, 0, 0, 0), 0, 0)); | ||
+ | prepare(); | ||
+ | setOpaque(false); | ||
+ | this.label.setOpenIcon(ClientUtils.getIcon("node.png")); | ||
+ | this.label.setClosedIcon(ClientUtils.getIcon("node.png")); | ||
+ | this.label.setLeafIcon(ClientUtils.getIcon("leaf.png")); | ||
+ | } | ||
+ | |||
+ | public void setEnabled(boolean enabled) | ||
+ | { | ||
+ | super.setEnabled(enabled); | ||
+ | this.check.setEnabled(enabled); | ||
+ | } | ||
+ | |||
+ | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) | ||
+ | { | ||
+ | prepare(); | ||
+ | |||
+ | this.label.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); | ||
+ | |||
+ | if ((value instanceof DefaultMutableTreeNode)) | ||
+ | { | ||
+ | setEnabled(tree.isEnabled()); | ||
+ | this.check.setEnabled(true); | ||
+ | DefaultMutableTreeNode serviceLabelTreeNode = (DefaultMutableTreeNode)value; | ||
+ | Object userObject = serviceLabelTreeNode.getUserObject(); | ||
+ | if ((userObject instanceof ServiceLabelItem)) | ||
+ | { | ||
+ | this.check.setSelected(((ServiceLabelItem)userObject).isSelected()); | ||
+ | } | ||
+ | this.check.setVisible(!serviceLabelTreeNode.isRoot()); | ||
+ | } | ||
+ | invalidate(); | ||
+ | return this; | ||
+ | } | ||
+ | |||
+ | public final DefaultTreeCellRenderer getTreeCellRenderer() | ||
+ | { | ||
+ | return this.label; | ||
+ | } | ||
+ | |||
+ | private void prepare() | ||
+ | { | ||
+ | Color bColor = UIManager.getColor("Tree.textBackground"); | ||
+ | setBackground(bColor); | ||
+ | this.check.setBackground(bColor); | ||
+ | this.label.setBackgroundNonSelectionColor(bColor); | ||
+ | this.label.setBackgroundSelectionColor(bColor); | ||
+ | this.label.setBackground(bColor); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | |||
+ | = Сервер = | ||
+ | == Таблицы mysql == | ||
+ | Таблицы аналогичны таблицам меток тарифов tariff_label и tariff_label_link | ||
+ | |||
+ | <source lang="sql"> | ||
+ | CREATE TABLE `custom_service_label` ( | ||
+ | `id` int(11) NOT NULL AUTO_INCREMENT, | ||
+ | `parent_id` int(11) NOT NULL DEFAULT '0', | ||
+ | `title` varchar(255) NOT NULL DEFAULT '', | ||
+ | PRIMARY KEY (`id`) | ||
+ | ) | ||
+ | |||
+ | CREATE TABLE `custom_service_label_link` ( | ||
+ | `sid` int(11) NOT NULL DEFAULT '0', | ||
+ | `label_id` int(11) NOT NULL DEFAULT '0', | ||
+ | KEY `sid` (`sid`,`label_id`) | ||
+ | ) | ||
+ | </source> | ||
+ | |||
+ | == Классы java == | ||
+ | |||
+ | Реализация веб-сервиса меток услуг | ||
+ | <source lang="java"> | ||
+ | package ru.bitel.bgbilling.kernel.module.server.service; | ||
+ | |||
+ | import ru.bitel.bgbilling.common.BGException; | ||
+ | import ru.bitel.bgbilling.kernel.container.service.server.AbstractService; | ||
+ | import ru.bitel.bgbilling.kernel.module.common.bean.BGModule; | ||
+ | import ru.bitel.bgbilling.kernel.module.common.bean.Service; | ||
+ | import ru.bitel.bgbilling.kernel.module.common.service.ServiceLabelService; | ||
+ | import ru.bitel.bgbilling.kernel.module.server.bean.ModuleManager; | ||
+ | import ru.bitel.bgbilling.kernel.module.server.bean.ServiceManager; | ||
+ | import ru.dsi.bgbilling.kernel.module.common.bean.ServiceItem; | ||
+ | import ru.dsi.bgbilling.kernel.module.common.bean.ServiceLabelItem; | ||
+ | import ru.dsi.bgbilling.kernel.module.server.bean.ServiceLabelDao; | ||
+ | |||
+ | import javax.jws.WebParam; | ||
+ | import javax.jws.WebService; | ||
+ | import java.sql.Connection; | ||
+ | import java.util.*; | ||
+ | |||
+ | /** | ||
+ | * Вебсервис для работы с метками (группами) услуг | ||
+ | */ | ||
+ | @WebService(endpointInterface="ru.bitel.bgbilling.kernel.module.common.service.ServiceLabelService") | ||
+ | public class ServiceLabelServiceImpl extends AbstractService | ||
+ | implements ServiceLabelService { | ||
+ | @Override | ||
+ | public List<ServiceLabelItem> getServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId) throws BGException { | ||
+ | ServiceLabelDao serviceLabelManager = new ServiceLabelDao(getConnection()); | ||
+ | List<ServiceLabelItem> serviceLabelItems = serviceLabelManager.getServiceLabelItemList(); | ||
+ | if (serviceId > 0) | ||
+ | { | ||
+ | Set<Integer> serviceLabelSet = serviceLabelManager.getServiceLabelIds(serviceId); | ||
+ | for (ServiceLabelItem serviceLabelItem : serviceLabelItems) | ||
+ | { | ||
+ | serviceLabelItem.setSelected(serviceLabelSet.contains(Integer.valueOf(serviceLabelItem.getId()))); | ||
+ | } | ||
+ | } | ||
+ | return serviceLabelItems; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void setServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId, | ||
+ | @WebParam(name="items") List<ServiceLabelItem> items) throws BGException { | ||
+ | Set<Integer> labelIds = new HashSet<Integer>(); | ||
+ | if (items != null) | ||
+ | { | ||
+ | for (ServiceLabelItem tariffLabelItem : items) | ||
+ | { | ||
+ | labelIds.add(tariffLabelItem.getId()); | ||
+ | } | ||
+ | } | ||
+ | new ServiceLabelDao(getConnection()).setServiceLabelIds(serviceId, labelIds); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int updateServiceLabelTreeItem(@WebParam(name = "serviceLabelItem") ServiceLabelItem serviceLabelItem) throws BGException { | ||
+ | new ServiceLabelDao(getConnection()).updateServiceLabelTreeItem(serviceLabelItem); | ||
+ | return serviceLabelItem != null ? serviceLabelItem.getId() : -1; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void removeServiceLabelTreeItem(@WebParam(name = "serviceLabelItemId") int serviceLabelItemId) throws BGException { | ||
+ | new ServiceLabelDao(getConnection()).removeServiceLabelItem(serviceLabelItemId); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public List<ServiceItem> getServiceList(@WebParam(name = "moduleIds") Set<Integer> moduleIds, @WebParam(name = "serviceLabelIds") List<Integer> serviceLabelIds) throws BGException { | ||
+ | List<ServiceItem> result = new ArrayList<ServiceItem>(); | ||
+ | Connection con = getConnection(); | ||
+ | ServiceManager sm = new ServiceManager(con); | ||
+ | ModuleManager mm = new ModuleManager(con); | ||
+ | ServiceLabelDao slDao = new ServiceLabelDao(con); | ||
+ | Map<Integer,BGModule> modulesMap = mm.getModulesMap(); | ||
+ | List<Service> services = sm.list(); | ||
+ | ServiceItem serviceItem; | ||
+ | BGModule module; | ||
+ | boolean found; | ||
+ | for(Service service : services){ | ||
+ | if(moduleIds!=null && moduleIds.size()>0){ | ||
+ | if(!moduleIds.contains(service.getModuleId())){ | ||
+ | continue; | ||
+ | } | ||
+ | } | ||
+ | Set<Integer> labelIds = slDao.getServiceLabelIds(service.getId()); | ||
+ | if(serviceLabelIds!=null && serviceLabelIds.size()>0){ | ||
+ | found = false;//Ищем, есть ли у услуги хотя бы одна метка из фильтра serviceLabelIds | ||
+ | for(Integer label_id : serviceLabelIds){ | ||
+ | if(labelIds.contains(label_id)){ | ||
+ | found = true; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | if(!found){ | ||
+ | continue; | ||
+ | } | ||
+ | } | ||
+ | //всё ок - добавляем услугу в список | ||
+ | serviceItem = new ServiceItem(); | ||
+ | serviceItem.setId(service.getId()); | ||
+ | serviceItem.setTitle(service.getTitle()); | ||
+ | serviceItem.setModuleId(service.getModuleId()); | ||
+ | serviceItem.setUsing(service.isUsing()); | ||
+ | serviceItem.setLabelCount(labelIds.size()); | ||
+ | module = modulesMap.get(service.getModuleId()); | ||
+ | serviceItem.setModuleTitle(module == null ? "???" : module.getTitle()); | ||
+ | result.add(serviceItem); | ||
+ | } | ||
+ | sm.recycle(); | ||
+ | return result; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Dao для работы с метками (группами) услуг: | ||
+ | <source lang="java"> | ||
+ | package ru.dsi.bgbilling.kernel.module.server.bean; | ||
+ | |||
+ | import ru.bitel.bgbilling.common.BGException; | ||
+ | import ru.bitel.bgbilling.server.util.ServerUtils; | ||
+ | import ru.dsi.bgbilling.kernel.module.common.bean.ServiceLabelItem; | ||
+ | |||
+ | import java.sql.*; | ||
+ | import java.util.*; | ||
+ | |||
+ | /** | ||
+ | * Dao для работы с метками (группами) услуг | ||
+ | */ | ||
+ | public class ServiceLabelDao { | ||
+ | protected static final String TABLE_SERVICE_LABEL = "custom_service_label"; | ||
+ | protected static final String TABLE_SERVICE_LABEL_LINK = "custom_service_label_link"; | ||
+ | private Connection con; | ||
+ | |||
+ | public ServiceLabelDao(Connection con) | ||
+ | { | ||
+ | this.con = con; | ||
+ | } | ||
+ | |||
+ | public List<ServiceLabelItem> getServiceLabelItemList() | ||
+ | throws BGException | ||
+ | { | ||
+ | List<ServiceLabelItem> result = new ArrayList<ServiceLabelItem>(); | ||
+ | try | ||
+ | { | ||
+ | Map<Integer, ServiceLabelItem> map = new HashMap<Integer, ServiceLabelItem>(); | ||
+ | |||
+ | Statement st = this.con.createStatement(); | ||
+ | |||
+ | StringBuilder query = | ||
+ | new StringBuilder("SELECT * FROM ") | ||
+ | .append(TABLE_SERVICE_LABEL) | ||
+ | .append(" ORDER BY title"); | ||
+ | ResultSet rs = st.executeQuery(query.toString()); | ||
+ | while (rs.next()) | ||
+ | { | ||
+ | ServiceLabelItem serviceLabelItem = getServiceLabelItemFromRS(rs); | ||
+ | map.put(serviceLabelItem.getId(), serviceLabelItem); | ||
+ | result.add(serviceLabelItem); | ||
+ | } | ||
+ | rs.close(); | ||
+ | |||
+ | query.setLength(0); | ||
+ | query.append("SELECT label_id, count(*) FROM ").append(TABLE_SERVICE_LABEL_LINK).append(" GROUP BY label_id"); | ||
+ | rs = st.executeQuery(query.toString()); | ||
+ | while (rs.next()) | ||
+ | { | ||
+ | ServiceLabelItem serviceLabelItem = map.get(rs.getInt(1)); | ||
+ | if (serviceLabelItem != null) | ||
+ | { | ||
+ | serviceLabelItem.setServiceLinkCount(rs.getInt(2)); | ||
+ | } | ||
+ | } | ||
+ | rs.close(); | ||
+ | |||
+ | st.close(); | ||
+ | } | ||
+ | catch (Exception ex) | ||
+ | { | ||
+ | throw new BGException(ex); | ||
+ | } | ||
+ | return result; | ||
+ | } | ||
+ | |||
+ | public Set<Integer> getServiceLabelIds(int serviceId) | ||
+ | throws BGException | ||
+ | { | ||
+ | Set<Integer> result = new HashSet<Integer>(); | ||
+ | try | ||
+ | { | ||
+ | String query = "SELECT label_id FROM " + TABLE_SERVICE_LABEL_LINK + " WHERE sid=" + serviceId; | ||
+ | Statement st = this.con.createStatement(); | ||
+ | ResultSet rs = st.executeQuery(query); | ||
+ | while (rs.next()) | ||
+ | { | ||
+ | result.add(rs.getInt(1)); | ||
+ | } | ||
+ | rs.close(); | ||
+ | st.close(); | ||
+ | } | ||
+ | catch (Exception ex) | ||
+ | { | ||
+ | throw new BGException(ex); | ||
+ | } | ||
+ | return result; | ||
+ | } | ||
+ | |||
+ | public void setServiceLabelIds(int serviceId, Set<Integer> labelIds) | ||
+ | throws BGException | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | StringBuilder query = new StringBuilder("DELETE FROM ").append(TABLE_SERVICE_LABEL_LINK) | ||
+ | .append(" WHERE sid=").append(serviceId); | ||
+ | Statement st = this.con.createStatement(); | ||
+ | st.executeUpdate(query.toString()); | ||
+ | st.close(); | ||
+ | |||
+ | query.setLength(0); | ||
+ | query.append("INSERT INTO ").append(TABLE_SERVICE_LABEL_LINK).append(" SET sid=").append(serviceId).append(", label_id=?"); | ||
+ | PreparedStatement ps = this.con.prepareStatement(query.toString()); | ||
+ | for (Integer id : labelIds) | ||
+ | { | ||
+ | ps.setInt(1, id); | ||
+ | ps.executeUpdate(); | ||
+ | } | ||
+ | ps.close(); | ||
+ | } | ||
+ | catch (Exception ex) | ||
+ | { | ||
+ | throw new BGException(ex); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public void updateServiceLabelTreeItem(ServiceLabelItem serviceLabelItem) | ||
+ | throws BGException | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | if (serviceLabelItem == null) | ||
+ | { | ||
+ | throw new NullPointerException("serviceLabelItem is null!"); | ||
+ | } | ||
+ | |||
+ | StringBuilder query = new StringBuilder(); | ||
+ | |||
+ | if (serviceLabelItem.getId() > 0) | ||
+ | { | ||
+ | query.append("UPDATE "); | ||
+ | query.append(TABLE_SERVICE_LABEL); | ||
+ | query.append(" SET parent_id=?, title=? WHERE id=?"); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | query.append("INSERT INTO "); | ||
+ | query.append(TABLE_SERVICE_LABEL); | ||
+ | query.append(" SET parent_id=?, title=?"); | ||
+ | } | ||
+ | |||
+ | PreparedStatement ps = this.con.prepareStatement(query.toString()); | ||
+ | ps.setInt(1, serviceLabelItem.getParentId()); | ||
+ | ps.setString(2, serviceLabelItem.getTitle()); | ||
+ | |||
+ | if (serviceLabelItem.getId() > 0) | ||
+ | { | ||
+ | ps.setInt(3, serviceLabelItem.getId()); | ||
+ | } | ||
+ | |||
+ | ps.executeUpdate(); | ||
+ | |||
+ | if (serviceLabelItem.getId() < 0) | ||
+ | { | ||
+ | serviceLabelItem.setId(ServerUtils.lastInsertId(this.con)); | ||
+ | } | ||
+ | |||
+ | ps.close(); | ||
+ | } | ||
+ | catch (Exception ex) | ||
+ | { | ||
+ | throw new BGException(ex); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public void removeServiceLabelItem(int serviceLabelItemId) | ||
+ | throws BGException | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | Statement st = this.con.createStatement(); | ||
+ | |||
+ | StringBuilder query = new StringBuilder("DELETE FROM ").append(TABLE_SERVICE_LABEL_LINK) | ||
+ | .append(" WHERE label_id=").append(serviceLabelItemId); | ||
+ | st.executeUpdate(query.toString()); | ||
+ | |||
+ | query.setLength(0); | ||
+ | query.append("DELETE FROM ").append(TABLE_SERVICE_LABEL).append(" WHERE id=").append(serviceLabelItemId); | ||
+ | st.executeUpdate(query.toString()); | ||
+ | |||
+ | st.close(); | ||
+ | } | ||
+ | catch (Exception ex) | ||
+ | { | ||
+ | throw new BGException(ex); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /*public List<ServiceItem> getServices(int moduleId, List<Integer> serviceLabelIds) | ||
+ | throws BGException { | ||
+ | try { | ||
+ | StringBuilder sb = new StringBuilder("SELECT * FROM service s "). | ||
+ | append("left join module m on s.mid=m.id "). | ||
+ | append("left join " + TABLE_SERVICE_LABEL_LINK + " sll on s.id=sll.sid "). | ||
+ | append("WHERE 1 "); | ||
+ | if(moduleId>0){ | ||
+ | sb.append("AND s.mid=").append(moduleId).append(" "); | ||
+ | } | ||
+ | if(serviceLabelIds!=null && serviceLabelIds.size()>0){ | ||
+ | sb.append("AND sll.label_id in (") | ||
+ | .append(Utils.toString(serviceLabelIds)) | ||
+ | .append(") "); | ||
+ | } | ||
+ | sb.append("GROUP BY ") | ||
+ | |||
+ | PreparedStatement ps = this.con.prepareStatement(); | ||
+ | } catch (SQLException e) { | ||
+ | throw new BGException(e); | ||
+ | } | ||
+ | |||
+ | ServiceManager sm = new ServiceManager(this.con); | ||
+ | List<Service> serviceList = sm.list(moduleId); | ||
+ | for(Service service: serviceList){ | ||
+ | service. | ||
+ | } | ||
+ | sm.recycle(); | ||
+ | }*/ | ||
+ | |||
+ | private ServiceLabelItem getServiceLabelItemFromRS(ResultSet rs) | ||
+ | throws SQLException | ||
+ | { | ||
+ | ServiceLabelItem serviceLabelItem = new ServiceLabelItem(); | ||
+ | serviceLabelItem.setId(rs.getInt("id")); | ||
+ | serviceLabelItem.setParentId(rs.getInt("parent_id")); | ||
+ | serviceLabelItem.setTitle(rs.getString("title")); | ||
+ | return serviceLabelItem; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | = Клиентские классы = |
Версия 08:01, 21 апреля 2013
Содержание |
Описание
Для отчётов полезно иметь группировку услуг по типам вне зависимости от модуля. Например, группа услуг "Интернет" - туда могут входить как услуги трафиков модулей Inet, Dialup, IPN, так и абонплаты за интернет. Аналогично, "VPN"
Было решено сделать группировку аналогично меткам тарифов - в виде дерева меток.
Решение состоит из серверного API и клиентского интерфейса. Решение является упрощённой копипастой работы с метками тарифов.
Общие классы
Классы, которые должны быть как в серверных библиотеках, так и в клиентских
Во-первых, нам понадобится веб-сервис для работы с метками тарифов:
package ru.bitel.bgbilling.kernel.module.common.service; import ru.bitel.bgbilling.common.BGException; import ru.dsi.bgbilling.kernel.module.common.bean.ServiceItem; import ru.dsi.bgbilling.kernel.module.common.bean.ServiceLabelItem; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import java.util.List; import java.util.Set; @WebService public abstract interface ServiceLabelService { @WebMethod public abstract List<ServiceLabelItem> getServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId) throws BGException; @WebMethod public abstract void setServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId, @WebParam(name="items") List<ServiceLabelItem> items) throws BGException; @WebMethod public abstract int updateServiceLabelTreeItem(@WebParam(name="serviceLabelItem") ServiceLabelItem serviceLabelItem) throws BGException; @WebMethod public abstract void removeServiceLabelTreeItem(@WebParam(name="serviceLabelItemId") int serviceLabelItemId) throws BGException; @WebMethod public abstract List<ServiceItem> getServiceList(@WebParam(name="moduleIds") Set<Integer> moduleIds, @WebParam(name="serviceLabelIds") List<Integer> serviceLabelIds) throws BGException; }
Элемент списка услуг для отображения:
package ru.dsi.bgbilling.kernel.module.common.bean; import ru.bitel.common.model.IdTitle; import javax.xml.bind.annotation.XmlAttribute; /** * Услуга, расширенная доп информацией */ public class ServiceItem extends IdTitle{ private int labelCount; private String moduleTitle; private int moduleId; private boolean using; @XmlAttribute public int getLabelCount() { return labelCount; } public void setLabelCount(int labelCount) { this.labelCount = labelCount; } @XmlAttribute public String getModuleTitle() { return moduleTitle; } public void setModuleTitle(String moduleTitle) { this.moduleTitle = moduleTitle; } @XmlAttribute public int getModuleId() { return this.moduleId; } public void setModuleId(int moduleId) { this.moduleId = moduleId; } @XmlAttribute public boolean isUsing() { return this.using; } public void setUsing(boolean used) { this.using = used; } }
Элемент дерева меток:
package ru.dsi.bgbilling.kernel.module.common.bean; import ru.bitel.common.model.IdTitle; import javax.xml.bind.annotation.XmlAttribute; public class ServiceLabelItem extends IdTitle { private int parentId = -1; private int serviceLinkCount = 0; private boolean selected = false; @XmlAttribute public int getParentId() { return this.parentId; } public void setParentId(int parentId) { this.parentId = parentId; } @XmlAttribute public int getServiceLinkCount() { return this.serviceLinkCount; } public void setServiceLinkCount(int serviceLinkCount) { this.serviceLinkCount = serviceLinkCount; } @XmlAttribute public boolean isSelected() { return this.selected; } public void setSelected(boolean selected) { this.selected = selected; } }
Renderer дерева меток:
package ru.dsi.bgbilling.kernel.module.common.bean; import ru.bitel.bgbilling.client.util.ClientUtils; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellRenderer; import java.awt.*; public class ServiceLabelTreeCellRenderer extends JPanel implements TreeCellRenderer { private JCheckBox check; private DefaultTreeCellRenderer label; public ServiceLabelTreeCellRenderer() { setLayout(new GridBagLayout()); add(this.check = new JCheckBox(), new GridBagConstraints(0, 0, 1, 1, 0.0D, 0.0D, 17, 0, new Insets(0, 0, 0, 0), 0, 0)); add(this.label = new DefaultTreeCellRenderer(), new GridBagConstraints(1, 0, 1, 1, 0.0D, 0.0D, 17, 0, new Insets(0, 0, 0, 0), 0, 0)); prepare(); setOpaque(false); this.label.setOpenIcon(ClientUtils.getIcon("node.png")); this.label.setClosedIcon(ClientUtils.getIcon("node.png")); this.label.setLeafIcon(ClientUtils.getIcon("leaf.png")); } public void setEnabled(boolean enabled) { super.setEnabled(enabled); this.check.setEnabled(enabled); } public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { prepare(); this.label.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); if ((value instanceof DefaultMutableTreeNode)) { setEnabled(tree.isEnabled()); this.check.setEnabled(true); DefaultMutableTreeNode serviceLabelTreeNode = (DefaultMutableTreeNode)value; Object userObject = serviceLabelTreeNode.getUserObject(); if ((userObject instanceof ServiceLabelItem)) { this.check.setSelected(((ServiceLabelItem)userObject).isSelected()); } this.check.setVisible(!serviceLabelTreeNode.isRoot()); } invalidate(); return this; } public final DefaultTreeCellRenderer getTreeCellRenderer() { return this.label; } private void prepare() { Color bColor = UIManager.getColor("Tree.textBackground"); setBackground(bColor); this.check.setBackground(bColor); this.label.setBackgroundNonSelectionColor(bColor); this.label.setBackgroundSelectionColor(bColor); this.label.setBackground(bColor); } }
Сервер
Таблицы mysql
Таблицы аналогичны таблицам меток тарифов tariff_label и tariff_label_link
CREATE TABLE `custom_service_label` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) NOT NULL DEFAULT '0', `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) CREATE TABLE `custom_service_label_link` ( `sid` int(11) NOT NULL DEFAULT '0', `label_id` int(11) NOT NULL DEFAULT '0', KEY `sid` (`sid`,`label_id`) )
Классы java
Реализация веб-сервиса меток услуг
package ru.bitel.bgbilling.kernel.module.server.service; import ru.bitel.bgbilling.common.BGException; import ru.bitel.bgbilling.kernel.container.service.server.AbstractService; import ru.bitel.bgbilling.kernel.module.common.bean.BGModule; import ru.bitel.bgbilling.kernel.module.common.bean.Service; import ru.bitel.bgbilling.kernel.module.common.service.ServiceLabelService; import ru.bitel.bgbilling.kernel.module.server.bean.ModuleManager; import ru.bitel.bgbilling.kernel.module.server.bean.ServiceManager; import ru.dsi.bgbilling.kernel.module.common.bean.ServiceItem; import ru.dsi.bgbilling.kernel.module.common.bean.ServiceLabelItem; import ru.dsi.bgbilling.kernel.module.server.bean.ServiceLabelDao; import javax.jws.WebParam; import javax.jws.WebService; import java.sql.Connection; import java.util.*; /** * Вебсервис для работы с метками (группами) услуг */ @WebService(endpointInterface="ru.bitel.bgbilling.kernel.module.common.service.ServiceLabelService") public class ServiceLabelServiceImpl extends AbstractService implements ServiceLabelService { @Override public List<ServiceLabelItem> getServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId) throws BGException { ServiceLabelDao serviceLabelManager = new ServiceLabelDao(getConnection()); List<ServiceLabelItem> serviceLabelItems = serviceLabelManager.getServiceLabelItemList(); if (serviceId > 0) { Set<Integer> serviceLabelSet = serviceLabelManager.getServiceLabelIds(serviceId); for (ServiceLabelItem serviceLabelItem : serviceLabelItems) { serviceLabelItem.setSelected(serviceLabelSet.contains(Integer.valueOf(serviceLabelItem.getId()))); } } return serviceLabelItems; } @Override public void setServiceLabelTreeItemList(@WebParam(name="serviceId") int serviceId, @WebParam(name="items") List<ServiceLabelItem> items) throws BGException { Set<Integer> labelIds = new HashSet<Integer>(); if (items != null) { for (ServiceLabelItem tariffLabelItem : items) { labelIds.add(tariffLabelItem.getId()); } } new ServiceLabelDao(getConnection()).setServiceLabelIds(serviceId, labelIds); } @Override public int updateServiceLabelTreeItem(@WebParam(name = "serviceLabelItem") ServiceLabelItem serviceLabelItem) throws BGException { new ServiceLabelDao(getConnection()).updateServiceLabelTreeItem(serviceLabelItem); return serviceLabelItem != null ? serviceLabelItem.getId() : -1; } @Override public void removeServiceLabelTreeItem(@WebParam(name = "serviceLabelItemId") int serviceLabelItemId) throws BGException { new ServiceLabelDao(getConnection()).removeServiceLabelItem(serviceLabelItemId); } @Override public List<ServiceItem> getServiceList(@WebParam(name = "moduleIds") Set<Integer> moduleIds, @WebParam(name = "serviceLabelIds") List<Integer> serviceLabelIds) throws BGException { List<ServiceItem> result = new ArrayList<ServiceItem>(); Connection con = getConnection(); ServiceManager sm = new ServiceManager(con); ModuleManager mm = new ModuleManager(con); ServiceLabelDao slDao = new ServiceLabelDao(con); Map<Integer,BGModule> modulesMap = mm.getModulesMap(); List<Service> services = sm.list(); ServiceItem serviceItem; BGModule module; boolean found; for(Service service : services){ if(moduleIds!=null && moduleIds.size()>0){ if(!moduleIds.contains(service.getModuleId())){ continue; } } Set<Integer> labelIds = slDao.getServiceLabelIds(service.getId()); if(serviceLabelIds!=null && serviceLabelIds.size()>0){ found = false;//Ищем, есть ли у услуги хотя бы одна метка из фильтра serviceLabelIds for(Integer label_id : serviceLabelIds){ if(labelIds.contains(label_id)){ found = true; break; } } if(!found){ continue; } } //всё ок - добавляем услугу в список serviceItem = new ServiceItem(); serviceItem.setId(service.getId()); serviceItem.setTitle(service.getTitle()); serviceItem.setModuleId(service.getModuleId()); serviceItem.setUsing(service.isUsing()); serviceItem.setLabelCount(labelIds.size()); module = modulesMap.get(service.getModuleId()); serviceItem.setModuleTitle(module == null ? "???" : module.getTitle()); result.add(serviceItem); } sm.recycle(); return result; } }
Dao для работы с метками (группами) услуг:
package ru.dsi.bgbilling.kernel.module.server.bean; import ru.bitel.bgbilling.common.BGException; import ru.bitel.bgbilling.server.util.ServerUtils; import ru.dsi.bgbilling.kernel.module.common.bean.ServiceLabelItem; import java.sql.*; import java.util.*; /** * Dao для работы с метками (группами) услуг */ public class ServiceLabelDao { protected static final String TABLE_SERVICE_LABEL = "custom_service_label"; protected static final String TABLE_SERVICE_LABEL_LINK = "custom_service_label_link"; private Connection con; public ServiceLabelDao(Connection con) { this.con = con; } public List<ServiceLabelItem> getServiceLabelItemList() throws BGException { List<ServiceLabelItem> result = new ArrayList<ServiceLabelItem>(); try { Map<Integer, ServiceLabelItem> map = new HashMap<Integer, ServiceLabelItem>(); Statement st = this.con.createStatement(); StringBuilder query = new StringBuilder("SELECT * FROM ") .append(TABLE_SERVICE_LABEL) .append(" ORDER BY title"); ResultSet rs = st.executeQuery(query.toString()); while (rs.next()) { ServiceLabelItem serviceLabelItem = getServiceLabelItemFromRS(rs); map.put(serviceLabelItem.getId(), serviceLabelItem); result.add(serviceLabelItem); } rs.close(); query.setLength(0); query.append("SELECT label_id, count(*) FROM ").append(TABLE_SERVICE_LABEL_LINK).append(" GROUP BY label_id"); rs = st.executeQuery(query.toString()); while (rs.next()) { ServiceLabelItem serviceLabelItem = map.get(rs.getInt(1)); if (serviceLabelItem != null) { serviceLabelItem.setServiceLinkCount(rs.getInt(2)); } } rs.close(); st.close(); } catch (Exception ex) { throw new BGException(ex); } return result; } public Set<Integer> getServiceLabelIds(int serviceId) throws BGException { Set<Integer> result = new HashSet<Integer>(); try { String query = "SELECT label_id FROM " + TABLE_SERVICE_LABEL_LINK + " WHERE sid=" + serviceId; Statement st = this.con.createStatement(); ResultSet rs = st.executeQuery(query); while (rs.next()) { result.add(rs.getInt(1)); } rs.close(); st.close(); } catch (Exception ex) { throw new BGException(ex); } return result; } public void setServiceLabelIds(int serviceId, Set<Integer> labelIds) throws BGException { try { StringBuilder query = new StringBuilder("DELETE FROM ").append(TABLE_SERVICE_LABEL_LINK) .append(" WHERE sid=").append(serviceId); Statement st = this.con.createStatement(); st.executeUpdate(query.toString()); st.close(); query.setLength(0); query.append("INSERT INTO ").append(TABLE_SERVICE_LABEL_LINK).append(" SET sid=").append(serviceId).append(", label_id=?"); PreparedStatement ps = this.con.prepareStatement(query.toString()); for (Integer id : labelIds) { ps.setInt(1, id); ps.executeUpdate(); } ps.close(); } catch (Exception ex) { throw new BGException(ex); } } public void updateServiceLabelTreeItem(ServiceLabelItem serviceLabelItem) throws BGException { try { if (serviceLabelItem == null) { throw new NullPointerException("serviceLabelItem is null!"); } StringBuilder query = new StringBuilder(); if (serviceLabelItem.getId() > 0) { query.append("UPDATE "); query.append(TABLE_SERVICE_LABEL); query.append(" SET parent_id=?, title=? WHERE id=?"); } else { query.append("INSERT INTO "); query.append(TABLE_SERVICE_LABEL); query.append(" SET parent_id=?, title=?"); } PreparedStatement ps = this.con.prepareStatement(query.toString()); ps.setInt(1, serviceLabelItem.getParentId()); ps.setString(2, serviceLabelItem.getTitle()); if (serviceLabelItem.getId() > 0) { ps.setInt(3, serviceLabelItem.getId()); } ps.executeUpdate(); if (serviceLabelItem.getId() < 0) { serviceLabelItem.setId(ServerUtils.lastInsertId(this.con)); } ps.close(); } catch (Exception ex) { throw new BGException(ex); } } public void removeServiceLabelItem(int serviceLabelItemId) throws BGException { try { Statement st = this.con.createStatement(); StringBuilder query = new StringBuilder("DELETE FROM ").append(TABLE_SERVICE_LABEL_LINK) .append(" WHERE label_id=").append(serviceLabelItemId); st.executeUpdate(query.toString()); query.setLength(0); query.append("DELETE FROM ").append(TABLE_SERVICE_LABEL).append(" WHERE id=").append(serviceLabelItemId); st.executeUpdate(query.toString()); st.close(); } catch (Exception ex) { throw new BGException(ex); } } /*public List<ServiceItem> getServices(int moduleId, List<Integer> serviceLabelIds) throws BGException { try { StringBuilder sb = new StringBuilder("SELECT * FROM service s "). append("left join module m on s.mid=m.id "). append("left join " + TABLE_SERVICE_LABEL_LINK + " sll on s.id=sll.sid "). append("WHERE 1 "); if(moduleId>0){ sb.append("AND s.mid=").append(moduleId).append(" "); } if(serviceLabelIds!=null && serviceLabelIds.size()>0){ sb.append("AND sll.label_id in (") .append(Utils.toString(serviceLabelIds)) .append(") "); } sb.append("GROUP BY ") PreparedStatement ps = this.con.prepareStatement(); } catch (SQLException e) { throw new BGException(e); } ServiceManager sm = new ServiceManager(this.con); List<Service> serviceList = sm.list(moduleId); for(Service service: serviceList){ service. } sm.recycle(); }*/ private ServiceLabelItem getServiceLabelItemFromRS(ResultSet rs) throws SQLException { ServiceLabelItem serviceLabelItem = new ServiceLabelItem(); serviceLabelItem.setId(rs.getInt("id")); serviceLabelItem.setParentId(rs.getInt("parent_id")); serviceLabelItem.setTitle(rs.getString("title")); return serviceLabelItem; } }