IP配置导出提交

This commit is contained in:
wangxin
2018-07-03 14:55:36 +08:00
parent abe373ced3
commit c74e75f306
14 changed files with 224 additions and 31 deletions

View File

@@ -10,6 +10,7 @@ package com.nis.domain.configuration;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.nis.util.excel.ExcelField;
/**
* @ClassName: BaseIpConfig.java
@@ -39,15 +40,24 @@ public class BaseIpCfg extends BaseCfg<BaseIpCfg> {
*/
@Expose
@SerializedName("ipType")
@ExcelField(title="ip_type",dictType="IP_TYPE")
protected Integer ipType;
@ExcelField(title="ip_pattern",dictType="IP_PATTERN")
protected Integer ipPattern;
@ExcelField(title="client_ip")
protected String srcIpAddress;
protected String destIpAddress;
protected Integer portPattern;
protected String srcPort;
@ExcelField(title="server_ip")
protected String destIpAddress;
@ExcelField(title="port_pattern",dictType="PORT_PATTERN")
protected Integer portPattern;
@ExcelField(title="client_port")
protected String srcPort;
@ExcelField(title="server_port")
protected String destPort;
protected Long dnsStrategyId;
@ExcelField(title="ir_type",dictType="IR_TYPE")
protected Integer irType;
@ExcelField(title="group_name")
protected String groupName;
/**

View File

@@ -7,6 +7,14 @@ import java.util.Map;
import com.google.gson.GsonBuilder;
public final class Constants {
/**
* 配置审核下发的类型 maat类型
*/
public static final int MAAT_TYPE=1;
/**
* 配置审核下发的类型 回调类型
*/
public static final int CALLBACK_TYPE=2;
/**
* IP验证正则
*/

View File

@@ -524,7 +524,9 @@ public class ExportExcel {
val = getBasicInfo(ef.dictType(),map,valStr);
}else{
//字典数据已做国际化处理
val = msgProp.get(DictUtils.getDictLabel(ef.dictType(), valStr, ""));
String dict=DictUtils.getDictLabel(ef.dictType(), valStr, "");
//如果找不到字典国际化值,把字典本身作为默认值放进去,不然导出就是空了
val = msgProp.getProperty(dict,dict);
}
}

View File

@@ -10,31 +10,36 @@ package com.nis.web.controller.configuration;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.jets3t.service.ServiceException;
import org.datanucleus.store.types.wrappers.backed.Set;
import org.springframework.beans.BeanUtils;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.nis.domain.Page;
import com.nis.domain.SysDataDictionaryItem;
import com.nis.domain.SysUser;
import com.nis.domain.basics.ServiceDictInfo;
import com.nis.domain.configuration.BaseIpCfg;
import com.nis.domain.configuration.HttpUrlCfg;
import com.nis.domain.configuration.IpCfgTemplate;
import com.nis.domain.configuration.IpPortCfg;
import com.nis.exceptions.MaatConvertException;
import com.nis.util.Constants;
import com.nis.util.DictUtils;
import com.nis.util.DateUtils;
import com.nis.util.StringUtil;
import com.nis.util.excel.ExportExcel;
import com.nis.util.excel.ImportExcel;
import com.nis.web.controller.BaseController;
import com.nis.web.dao.configuration.IpCfgDao;
@@ -213,7 +218,8 @@ public class CommonController extends BaseController {
addMessage(redirectAttributes, "audit_failed");
}
}
public void _importIp(RedirectAttributes redirectAttributes,MultipartFile file,IpPortCfg ipCfg) {
public void _importIp(String cfgName,RedirectAttributes redirectAttributes,MultipartFile file,IpPortCfg ipCfg) {
redirectAttributes.addAttribute("cfgName", cfgName);
try {
ImportExcel ei = new ImportExcel(file, 0, 0);
List<IpCfgTemplate> list = ei.getDataList(IpCfgTemplate.class);
@@ -239,9 +245,51 @@ public class CommonController extends BaseController {
e.printStackTrace();
}
}
@RequestMapping(value = "import/template")
public void _importFileTemplate(HttpServletRequest request,HttpServletResponse response,
RedirectAttributes redirectAttributes,Integer functionId,Integer cfgRegionCode) {
this.importCfgTemplate(request, response, redirectAttributes, functionId, cfgRegionCode);
}
//ip配置导出
public void _exportIp(Model model,HttpServletRequest request,HttpServletResponse response,
@ModelAttribute("cfg")IpPortCfg entity,String ids,RedirectAttributes redirectAttributes){
try {
//获取国际化配置
Properties msgProp = getMsgProp();
//获取分类、性质、标签
List<ServiceDictInfo> fls=serviceDictInfoService.findAllFlDict();
List<ServiceDictInfo> xzs=serviceDictInfoService.findAllXzDict();
List<ServiceDictInfo> labels=serviceDictInfoService.findAllLableDict();
Map<Object, Object> map=new HashMap<Object, Object>();
map.put("fls", fls);
map.put("xzs", xzs);
map.put("labels", labels);
String fileName = msgProp.getProperty("date_list", "data")+"-"+DateUtils.getDate("yyyyMMddHHmmss")+".xlsx";
//导出选中记录
if(!StringUtil.isEmpty(ids)){
for(String id:ids.split(",")){
Long.parseLong(id);
}
List<BaseIpCfg> list=ipCfgService.getListByCfgIdWithName(IpPortCfg.getTablename(), entity.getFunctionId(), ids);
new ExportExcel(msgProp,null, IpPortCfg.class,1).setDataList(msgProp,list,map).write(response, fileName).dispose();
}else{
//条件导出数据大于最大导出数,只导出最大导出条数
entity.setTableName(IpPortCfg.getTablename());
Page<BaseIpCfg> pageInfo=new Page<BaseIpCfg>(request, response,"r");
if(pageInfo.getCount()>Constants.MAX_EXPORT_SIZE){
pageInfo.setPageNo(1);
pageInfo.setPageSize(Constants.MAX_EXPORT_SIZE);
}else{
pageInfo.setPageNo(1);
pageInfo.setPageSize(-1);
}
Page<BaseIpCfg> page = ipCfgService.findPage(pageInfo, entity);
new ExportExcel(msgProp,null, IpPortCfg.class,1).setDataList(msgProp,page.getList(),map).write(response, fileName).dispose();
}
} catch (Exception e) {
e.printStackTrace();
addMessage(redirectAttributes, "导出失败!失败信息:"+e.getMessage());
}
}
}

View File

@@ -91,12 +91,24 @@ public class IpMultiplexController extends CommonController {
return "redirect:" + adminPath +"/manipulation/ipmulitiplex/list?functionId="+cfg.getFunctionId();
}
//ip配置导入
@RequestMapping(value = "/importIp", method=RequestMethod.POST)
public String importIp(RedirectAttributes redirectAttributes,
@RequestMapping(value = "/import", method=RequestMethod.POST)
public String importIp(String cfgName,RedirectAttributes redirectAttributes,
@RequestParam("file") MultipartFile file,IpPortCfg cfg) {
this._importIp(redirectAttributes, file,cfg);
this._importIp(cfgName,redirectAttributes, file,cfg);
redirectAttributes.addAttribute("urlPrefix","/manipulation/ipmulitiplex");
redirectAttributes.addAttribute("requiresPermissionPrefix","ip:mulitiplex");
return "redirect:" + adminPath +"/manipulation/ipmulitiplex/list?functionId="+cfg.getFunctionId();
}
//ip模板下载
@RequestMapping(value = "import/template")
public void importFileTemplate(HttpServletRequest request,HttpServletResponse response,
RedirectAttributes redirectAttributes,Integer functionId,Integer cfgRegionCode) {
this._importFileTemplate(request, response, redirectAttributes, functionId, cfgRegionCode);
}
//ip配置导出
@RequestMapping(value = "export")
public void exportIp(Model model,HttpServletRequest request,HttpServletResponse response,
@ModelAttribute("cfg")IpPortCfg entity,String ids,RedirectAttributes redirectAttributes){
this._exportIp(model, request, response, entity, ids, redirectAttributes);
}
}

View File

@@ -112,12 +112,23 @@ public class RatelimitController extends CommonController {
return "redirect:" + adminPath +"/manipulation/ratelimit/domain/list?functionId="+cfg.getFunctionId();
}
//ip配置导入
@RequestMapping(value = "/ip/importIp", method=RequestMethod.POST)
public String importIp(RedirectAttributes redirectAttributes,
@RequestMapping(value = "/ip/import", method=RequestMethod.POST)
public String importIp(String cfgName,RedirectAttributes redirectAttributes,
@RequestParam("file") MultipartFile file,IpPortCfg cfg) {
this._importIp(redirectAttributes, file,cfg);
this._importIp(cfgName,redirectAttributes, file,cfg);
redirectAttributes.addAttribute("urlPrefix","/manipulation/ratelimit/ip");
redirectAttributes.addAttribute("requiresPermissionPrefix","ip:ratelimit");
return "redirect:" + adminPath +"/manipulation/ratelimit/ip/list?functionId="+cfg.getFunctionId();
}
@RequestMapping(value = "/ip/import/template")
public void importFileTemplate(HttpServletRequest request,HttpServletResponse response,
RedirectAttributes redirectAttributes,Integer functionId,Integer cfgRegionCode) {
this._importFileTemplate(request, response, redirectAttributes, functionId, cfgRegionCode);
}
//ip配置导出
@RequestMapping(value = "/ip/export")
public void exportIp(Model model,HttpServletRequest request,HttpServletResponse response,
@ModelAttribute("cfg")IpPortCfg entity,String ids,RedirectAttributes redirectAttributes){
this._exportIp(model, request, response, entity, ids, redirectAttributes);
}
}

View File

@@ -64,12 +64,24 @@ public class IpController extends CommonController{
return "redirect:" + adminPath +"/ntc/iplist/list?functionId="+cfg.getFunctionId();
}
//ip配置导入
@RequestMapping(value = "importIp", method=RequestMethod.POST)
public String importIp(RedirectAttributes redirectAttributes,
@RequestMapping(value = "import", method=RequestMethod.POST)
public String importIp(String cfgName,RedirectAttributes redirectAttributes,
@RequestParam("file") MultipartFile file,IpPortCfg cfg) {
redirectAttributes.addAttribute("urlPrefix","/ntc/iplist");
redirectAttributes.addAttribute("requiresPermissionPrefix","iplist");
this._importIp(redirectAttributes, file,cfg);
this._importIp(cfgName,redirectAttributes, file,cfg);
return "redirect:" + adminPath +"/ntc/iplist/list?functionId="+cfg.getFunctionId();
}
//ip模板下载
@RequestMapping(value = "import/template")
public void importFileTemplate(HttpServletRequest request,HttpServletResponse response,
RedirectAttributes redirectAttributes,Integer functionId,Integer cfgRegionCode) {
this._importFileTemplate(request, response, redirectAttributes, functionId, cfgRegionCode);
}
//ip配置导出
@RequestMapping(value = "export")
public void exportIp(Model model,HttpServletRequest request,HttpServletResponse response,
@ModelAttribute("cfg")IpPortCfg entity,String ids,RedirectAttributes redirectAttributes){
this._exportIp(model, request, response, entity, ids, redirectAttributes);
}
}

View File

@@ -112,12 +112,23 @@ public class ControlController extends CommonController {
return "redirect:" + adminPath +"/proxy/control/domain/list?functionId="+cfg.getFunctionId();
}
//ip配置导入
@RequestMapping(value = "/ip/importIp", method=RequestMethod.POST)
public String importIp(RedirectAttributes redirectAttributes,
@RequestMapping(value = "/ip/import", method=RequestMethod.POST)
public String importIp(String cfgName,RedirectAttributes redirectAttributes,
@RequestParam("file") MultipartFile file,IpPortCfg cfg) {
this._importIp(redirectAttributes, file,cfg);
this._importIp(cfgName,redirectAttributes, file,cfg);
redirectAttributes.addAttribute("urlPrefix","/proxy/control/ip");
redirectAttributes.addAttribute("requiresPermissionPrefix","control:ip");
return "redirect:" + adminPath +"/proxy/control/ip/list?functionId="+cfg.getFunctionId();
}
@RequestMapping(value = "/ip/import/template")
public void importFileTemplate(HttpServletRequest request,HttpServletResponse response,
RedirectAttributes redirectAttributes,Integer functionId,Integer cfgRegionCode) {
this._importFileTemplate(request, response, redirectAttributes, functionId, cfgRegionCode);
}
//ip配置导出
@RequestMapping(value = "/ip/export")
public void exportIp(Model model,HttpServletRequest request,HttpServletResponse response,
@ModelAttribute("cfg")IpPortCfg entity,String ids,RedirectAttributes redirectAttributes){
this._exportIp(model, request, response, entity, ids, redirectAttributes);
}
}

View File

@@ -102,12 +102,23 @@ public class InterceptController extends CommonController{
return "redirect:" + adminPath +"/proxy/intercept/domain/list?functionId="+cfg.getFunctionId();
}
//ip配置导入
@RequestMapping(value = "/ip/importIp", method=RequestMethod.POST)
public String importIp(RedirectAttributes redirectAttributes,
@RequestMapping(value = "/ip/import", method=RequestMethod.POST)
public String importIp(String cfgName,RedirectAttributes redirectAttributes,
@RequestParam("file") MultipartFile file,IpPortCfg cfg) {
this._importIp(redirectAttributes, file,cfg);
this._importIp(cfgName,redirectAttributes, file,cfg);
redirectAttributes.addAttribute("urlPrefix","/proxy/intercept/ip");
redirectAttributes.addAttribute("requiresPermissionPrefix","intercept:ip");
return "redirect:" + adminPath +"/proxy/intercept/ip/list?functionId="+cfg.getFunctionId();
}
@RequestMapping(value = "/ip/import/template")
public void importFileTemplate(HttpServletRequest request,HttpServletResponse response,
RedirectAttributes redirectAttributes,Integer functionId,Integer cfgRegionCode) {
this._importFileTemplate(request, response, redirectAttributes, functionId, cfgRegionCode);
}
//ip配置导出
@RequestMapping(value = "/ip/export")
public void exportIp(Model model,HttpServletRequest request,HttpServletResponse response,
@ModelAttribute("cfg")IpPortCfg entity,String ids,RedirectAttributes redirectAttributes){
this._exportIp(model, request, response, entity, ids, redirectAttributes);
}
}

View File

@@ -19,6 +19,7 @@ public interface IpCfgDao extends CrudDao<BaseIpCfg>{
public BaseIpCfg get(BaseIpCfg entity) ;
public List<BaseIpCfg> findList(BaseIpCfg entity) ;
public List<BaseIpCfg> getListByCfgId(@Param("tableName")String tableName,@Param("functionId")int functionId,@Param("ids")String ids) ;
public List<BaseIpCfg> getListByCfgIdWithName(@Param("tableName")String tableName,@Param("functionId")int functionId,@Param("ids")String ids) ;
public List<BaseIpCfg> getListByComileId(@Param("tableName")String tableName,@Param("functionId")int functionId,@Param("ids")String ids) ;
public int insert(BaseIpCfg entity) ;
public int update(BaseIpCfg entity) ;

View File

@@ -52,6 +52,13 @@
SERVICE_ID,REQUEST_ID,COMPILE_ID,IS_AREA_EFFECTIVE,CLASSIFY,
ATTRIBUTE,LABLE,AREA_EFFECTIVE_IDS,FUNCTION_ID,RATELIMIT,DNS_STRATEGY_ID,IR_TYPE
</sql>
<sql id="BaseIpCfg_Column_List_with_id_name" >
CFG_ID, CFG_DESC,CFG_REGION_CODE,CFG_TYPE, IP_TYPE, IP_PATTERN, SRC_IP_ADDRESS,DEST_IP_ADDRESS, PORT_PATTERN,SRC_PORT,DEST_PORT,
DIRECTION,PROTOCOL,PROTOCOL_ID,ACTION,IS_VALID,IS_AUDIT,
CREATOR_ID,CREATE_TIME,EDITOR_ID,EDIT_TIME,AUDITOR_ID,AUDIT_TIME,
SERVICE_ID,REQUEST_ID,COMPILE_ID,IS_AREA_EFFECTIVE,CLASSIFY,
ATTRIBUTE,LABLE,AREA_EFFECTIVE_IDS,FUNCTION_ID,RATELIMIT,DNS_STRATEGY_ID,IR_TYPE
</sql>
<sql id="BaseIpCfg_Column_List_with_id_alias" >
<choose>
<when test="page !=null and page.alias != null and page.alias != ''">
@@ -580,4 +587,23 @@
<update id="deleteByCompileIds" parameterType="com.nis.domain.configuration.BaseIpCfg" >
update ${tableName} set is_valid = -1, editor_id = #{user,jdbcType=INTEGER} , edit_time = NOW() where compile_id in (${compileIds})
</update>
<select id="getListByCfgIdWithName" resultMap="BaseIpMapWithUser">
select
r.CFG_ID as cfgId, r.CFG_DESC as cfgDesc,r.CFG_REGION_CODE as cfgRegionCode,r.CFG_TYPE as cfgType, r.IP_TYPE as ipType,
r.IP_PATTERN as ipPattern, r.SRC_IP_ADDRESS as srcIpAddress, r.DEST_IP_ADDRESS as destIpAddress, r.PORT_PATTERN as portPattern,r.SRC_PORT as srcPort,r.DEST_PORT as destPort,
r.DIRECTION as direction,r.PROTOCOL as protocol,r.PROTOCOL_ID as protocolId,r.ACTION as action,r.IS_VALID as isValid,r.IS_AUDIT as isAudit,
r.CREATOR_ID as creatorId,r.CREATE_TIME AS createTime,r.EDITOR_ID as editorId,r.EDIT_TIME AS editTime,r.AUDITOR_ID as auditorId,r.AUDIT_TIME AS auditTime,
r.SERVICE_ID as serviceId,r.REQUEST_ID AS requestId,r.COMPILE_ID AS compileId,r.IS_AREA_EFFECTIVE as isAreaEffective,r.classify,
r.ATTRIBUTE AS attribute,r.LABLE AS lable,r.AREA_EFFECTIVE_IDS AS areaEffectiveIds,r.FUNCTION_ID as functionId,r.RATELIMIT AS ratelimit,
r.DNS_STRATEGY_ID AS dnsStrategyId,r.IR_TYPE AS irType
, s.name as creator_name,e.name as editor_name,u.name as auditor_name
,ri.request_title as requestName,po.group_name as group_name
from ${tableName} r
left join sys_user s on r.creator_id=s.id
left join sys_user e on r.editor_id=e.id
left join sys_user u on r.auditor_id=u.id
left join request_info ri on r.request_id=ri.id
left join policy_group_info po on r.dns_strategy_id=po.group_id
WHERE r.CFG_ID in (${ids}) AND r.FUNCTION_ID=#{functionId,jdbcType=INTEGER}
</select>
</mapper>

View File

@@ -15,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.nis.domain.FunctionRegionDict;
import com.nis.domain.SysDataDictionaryItem;
import com.nis.domain.callback.InlineIp;
import com.nis.domain.configuration.AreaIpCfg;
@@ -161,8 +162,18 @@ public class IpCfgService extends CrudService<IpCfgDao,BaseIpCfg> {
maatCfg.initDefaultValue();
BeanUtils.copyProperties(cfg, maatCfg);
String json="";
if(cfg.getIsAudit()==1){
if(Constants.SERVICE_IP_MULITIPLEX!=cfg.getServiceId().intValue() &&(Constants.DROP_ACTION==cfg.getAction()||Constants.LOOP_ACTION==cfg.getAction())){
//获取region
List<FunctionRegionDict> dictList = DictUtils.getFunctionRegionDictList(cfg.getFunctionId());
int maatType=0;
//判断下发类型是走maat还是callback
for(FunctionRegionDict f:dictList){
if(f.getCfgRegionCode().intValue()==cfg.getCfgRegionCode()){
maatType=f.getIsMaat();
break;
}
}
if(cfg.getIsAudit()==Constants.AUDIT_YES){
if(maatType==Constants.CALLBACK_TYPE){
List<InlineIp> ipList=new ArrayList<>();
InlineIp ip=convertCallBackIp(cfg,null);
ipList.add(ip);
@@ -179,7 +190,7 @@ public class IpCfgService extends CrudService<IpCfgDao,BaseIpCfg> {
logger.error("IP配置配置下发失败",e);
throw e;
}
}else{
}else if(maatType==Constants.MAAT_TYPE){
Map<String,List> map = cfgConvert(ipRegionList,beans,1,cfg,groupRelationList);
ipRegionList=map.get("dstList");
groupRelationList=map.get("groupList");
@@ -225,7 +236,7 @@ public class IpCfgService extends CrudService<IpCfgDao,BaseIpCfg> {
throw e;
}
}
}else if(cfg.getIsAudit()==3){
}else if(cfg.getIsAudit()==Constants.AUDIT_NOT_YET){
if(Constants.DROP_ACTION==cfg.getAction()||Constants.LOOP_ACTION==cfg.getAction()){
List<InlineIp> ipList=new ArrayList<>();
InlineIp ip=convertCallBackIp(cfg,null);
@@ -441,4 +452,19 @@ public class IpCfgService extends CrudService<IpCfgDao,BaseIpCfg> {
}
return compileId;
}
/**
* getListByCfgIdWithName(这里用一句话描述这个方法的作用)
* (这里描述这个方法适用条件 可选)
* @param tablename
* @param functionId
* @param ids
* @return
*List<BaseIpCfg>
* @exception
* @since 1.0.0
*/
public List<BaseIpCfg> getListByCfgIdWithName(String tablename, Integer functionId, String ids) {
// TODO Auto-generated method stub
return ipCfgDao.getListByCfgIdWithName(tablename,functionId,ids);
}
}

View File

@@ -6,7 +6,7 @@ $(function(){
});
</script>
<div class="modal fade" id="import_modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<form id="importForm1" action="${ctx}${urlPrefix}/importIp"
<form id="importForm1" action="${ctx}${urlPrefix}/import"
method="post" enctype="multipart/form-data" class="form-horizontal"
onsubmit="loading('<spring:message code='loading'/>');">
<input type="hidden" id="cfgRegionCode" name="cfgRegionCode" value="" />

View File

@@ -50,6 +50,20 @@
<!-- 模板导入start -->
<%@include file="/WEB-INF/include/excel/importIp.jsp" %>
<!-- 模板导入end -->
<div class="modal fade" id="export_all_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-header">
<h4 class="modal-title" id="myModalLabel"><spring:message code="confirm"/></h4>
</div>
<div class="modal-doby">
<h2 class=""><spring:message code="sure_to_export_all_data"/></h2>
</div>
<div class="modal-footer">
<button type="button" id="btn_confirm" class="btn btn-primary" data-dismiss="modal"><spring:message code="yes"/></button>
<button type="button" class="btn btn-default" data-dismiss="modal"><spring:message code="no"/></button>
</div>
</div>
</div>
<div class="theme-panel hidden-xs hidden-sm">
<shiro:hasPermission name="${requiresPermissionPrefix.concat(':config')}">
<button type="button" class="btn btn-primary"
@@ -128,6 +142,7 @@
<shiro:hasPermission name="${requiresPermissionPrefix.concat(':config')}">
<sys:delRow url="${ctx}${urlPrefix}/form?functionId=${cfg.functionId}&cfgName=${cfgName}" id="contentTable" label="update"></sys:delRow>
<sys:delRow url="${ctx}${urlPrefix}/delete?functionId=${cfg.functionId}&cfgName=${cfgName}" id="contentTable" label="delete"></sys:delRow>
<sys:delRow url="${ctx}${urlPrefix}/export?functionId=${cfg.functionId}" id="contentTable" label="export" maxRow="${page.maxExportSize}"></sys:delRow>
</shiro:hasPermission>
<shiro:hasPermission name="${requiresPermissionPrefix.concat(':config')}">
<div class="btn-group">