自定义数据集实现RBP用户资源列表报表需求
用户需求:
列出RBP用户资源列表,目前RBP的功能是提供单个用户的资源列表。用户需要按用户,按机构列出所选用户的资源权限列表。
该需求实现难点在于RBP的权限具有集成关系,目录可以设置继承,下级目录和资源可以继承或不集成该目录的权限。另外用户、机构和角色都可以作为权限的载体,一个用户的最终权限,是由用户本身的权限、用户机构的权限、用户角色的权限三部分组合而成。
介于资源权限逻辑的复杂性,不能通过一个简单的sql就完成逻辑判断得到数据查询结果。
实现思路:
1. 接口开发,遍历RBP的叶子资源,利用系统提供的资源权限判断方法,根据传入的userid和资源id,判断用户是否有资源访问权限,返回该用户有权限的资源列表。
2. 调用接口,完成自定义数据集类开发。调用上面接口,返回数据集结果(用户(多个)的资源列表)。该数据集的结构为resname,url,fatherid,userid。
3. 开发报表,调用自定义数据集生成数据集,在报表中完成分组报表设计。
具体实现:
1. 接口开发:ResPageUtils.java
该接口传入参数userId,返回用户相应资源列表。部分实现代码如下:
public class ResPageUtils {
public static List getResListbyUser(String userId){
List<ResInfo> list = new ArrayList<ResInfo>();
DBAccess dba = null;
ResultSet rs = null;
try {
dba = new DBAccess();
UserInfo user = “root”.equals(userId) ? null : new UserInfo(userId,dba);
HashMap pathMap = new HashMap();
HashMap nameMap = new HashMap();
rs = dba.executeQuery(“SELECT Res_ID,Res_FatherID,Res_Name FROM T_Res WHERE Res_Type=256 AND Res_IsLeaf=0 AND sys_statu=1″);
while (rs.next()) {
int resId = rs.getInt(“Res_ID”);
int fatherId = rs.getInt(“Res_FatherID”);
String resName = rs.getString(“Res_Name”);
pathMap.put(new Integer(resId), new Integer(fatherId));
nameMap.put(new Integer(resId), resName);
}
if (rs != null)
rs.close();
//查询出所有的叶子节点资源
rs = dba.executeQuery(“SELECT Res_ID,Res_Type,Res_Name,Res_Des,Res_FatherID,Res_HasArg,res_path FROM T_Res WHERE Res_ID>10000 AND Res_Type IN (4,8,16,32,64,128,512,10000,10001) AND Res_IsLeaf=1 AND sys_statu=1″);
ResInfo rif = null;
//遍历所有的叶子节点资源,判断资源对是否有读取权限,调用了底层基础类的方法Privilege.hasPrivileges,如果有,该资源加入到返回的资源列表中。
for (int i = 0; rs.next(); i++) {
rif = new ResInfo();
int resId = rs.getInt(“Res_ID”);//资源ID
int resType = rs.getInt(“Res_Type”);//资源类型
String resName = rs.getString(“Res_Name”);//资源名称
String resDesc = rs.getString(“Res_Des”);//资源描述
Integer fatherId = new Integer(rs.getInt(“Res_FatherID”));//资源父id
int Res_HasArg = rs.getInt(“Res_HasArg”);
String currResPath = rs.getString(“res_path”);//当前资源路径
if (!Privilege.hasPrivileges(user, resId, 1, dba))
continue;
// 获取资源的路径
String resPath = “”;
while (fatherId != null && fatherId.intValue() != -1) {
resPath = (String) nameMap.get(fatherId) + “>” + resPath;
fatherId = (Integer) pathMap.get(fatherId);
}
while (resPath.endsWith(“>”))
resPath = resPath.substring(0, resPath.length() – 1);
rif.setResID(resId);
rif.setResFatherID(fatherId);
rif.setResType(resType);
rif.setResDes(resDesc);
rif.setResName(resName);
rif.setResPath(resPath);
list.add(rif);
}
if (rs != null)
rs.close();
} catch (Exception e) {
//e.printStackTrace();
list = null;
//response.sendRedirect(request.getContextPath() + “/mis2/error.jsp”);
} finally {
if (dba != null){
dba.close();
}
}
return list;
}
}
2. 自定义数据集类开发
该类继承IDataSetFactory接口,实现接口定义的方法:public DataSet createDataSet(Context ctx, DataSetConfig dsc,boolean retrieve),并返回一个DataSet对象。根据出入的userid列表,循环调用ResPageUtils的getResListbyUser方法,查询多个用户的资源列表并作为数据集返回。部分实现代码:
public class userReslist implements IDataSetFactory{
public DataSet createDataSet(Context ctx, DataSetConfig dsc, boolean retrieve){
long time1 = System.currentTimeMillis();
Map map = ctx.getParamMap(false);
String[] idlist=null;
if( map != null ){
Iterator it = map.keySet().iterator();
while( it.hasNext() ){
//分别取得参数
String key = it.next().toString();
String value = map.get(key).toString();
System.out.println(“报表传入的参数”+key+”的值是:”+value);
//获取报表中的参数userlist,拆分成字符串组
if(key.equals(“userlist”)&&!value.equals(“”)){
idlist=value.split(“,”);
}
}
}
}
//构造一个数据集,添加列名
DataSet ds = new DataSet(“ds1″);
ResInfo res=new ResInfo();
ds.addCol( “resname” ); //列名
ds.addCol( “url” ); //列名
ds.addCol( “fatherid” ); //列名
ds.addCol(“userid”);
if(idlist!=null){
for(int j=0;j<idlist.length;j++){
System.out.println(idlist[j].toString());
String param=idlist[j].toString();
List<ResInfo> reslist = new ArrayList<ResInfo>();
try{
long time3 = System.currentTimeMillis();
//调用接口方法getResListbyUser获取用户资源list
reslist= ResPageUtils.getPageParamsList(idlist[j].toString());
long time4 = System.currentTimeMillis();
System.out.println(“计算人员ID为”+idlist[j].toString()+”的资源列表的时间为:>”+(time4-time3)+”ms”);
System.out.println(“================”);
}catch (Exception e){
System.out.println(“自定义异常: 数据不完整”);
}
//根据查询list的数据,设置数据集中的数据
for( int i = 0; i < reslist.size(); i++ ) {
//System.out.println( i );
res=reslist.get(i);
Row row = ds.addRow();
row.setData(1, res.getResName());
row.setData(2, res.getResPath());
row.setData(3, res.getResFatherID());
row.setData(4,idlist[j]);
}
}
}
long time2 = System.currentTimeMillis();
System.out.println(“数据集创建总时间:>”+(time2-time1)+”ms”);
return ds;
}
}
3. 报表模板实现
1)参数:
普通参数:userid 字符串型,orgid字符串组型,这两个参数分别接收参数表单传递过来的用户id和机构id,其中机构id在参数表单中采用可多选的下拉树模式供用户选择。
动态参数:if(userid!=null&&userid!=”",query2(“mis2datasource”,”select user_id from t_user where user_id=?”,userid),orgid!=null&&orgid!=”",query2(“mis2datasource”,”select user_ID from rt_orguser where user_id!=’root’ and org_id in (?)”,orgid))
根据普通参数userid,orgid,动态计算需要查询的用户id列表(多个用户id用,分割)。
2)数据集:
ds1: select a.user_id,a.user_name,b.org_id,e.org_name, c.role_id,d.role_name from t_user a, rt_orguser b, rt_roleuser c, t_role d, t_org e where a.user_id=b.user_id and a.user_id=c.user_id and b.org_id=e.org_id and c.role_id=d.role_id and a.user_id!=’root’ and a.user_id in(?)
参数:split(userlist,”,”)
该数据集可以得到待查询的用户的机构,角色,用户名等用户基本信息。
ds2:采用自定义数据集的方式,此时选择数据集的类型为自定义,然后在编辑界面中输入类名和需要用到的参数。报表运算时,就会自动执行createDataSet()方法来取得报表运算所需要的数据集。
3)报表模板设计:
A2:设置隐藏行属性,在没有查到用户时,该行显示,否则该行隐藏。
其中A4~C4单元格先按机构分组再按用户id分组,E4单元格:=ds2.Select(resname,false,userid==B4,url+”0″+resname)进行数据集间关联,查出ds2中userid和B4单元格值相等记录,并按照路径和资源名称的升序排列。
实现效果: