惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
Y
Y Combinator Blog
Engineering at Meta
Engineering at Meta
D
Docker
GbyAI
GbyAI
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
腾讯CDC
P
Proofpoint News Feed
A
About on SuperTechFans
WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
Google DeepMind News
Google DeepMind News
C
Check Point Blog
Microsoft Security Blog
Microsoft Security Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
MyScale Blog
MyScale Blog
博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
Microsoft Azure Blog
Microsoft Azure Blog
N
Netflix TechBlog - Medium
G
Google Developers Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

博客园 - gcg0036

亚信仨月印象(国庆时再写) 博客搬家了! log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable. 模板引擎Crox用法大全(更新版) Apache Tomcat Maven Plugin 参数大全(Tomcat 6) Apache Tomcat Maven Plugin MyEclipse 2015 CI 12 无限试用 sshe源码分析——全局架构 无聊的三月终于过去了 failed to initialize monitor thread 在Android项目中的测试类点击"run as JUnit test"出错 Interacting with Other Apps Saving Data Managing the Activity Lifecycle Adding the Action Bar Building Your First App The AndroidManifest.xml File handlebars简单用法 高性能跨语言模板引擎Crox
sshe源码分析——权限管理的后台部分
gcg0036 · 2015-04-05 · via 博客园 - gcg0036

数据库结构:

wpsEACA.tmp 

用户跟组织:多对对

用户跟角色:多对多

组织:有上级组织

wpsEACB.tmp 

资源跟组织:多对多

资源跟角色:多对多

资源:有上级资源

资源:有资源类型

BaseDaoImpl中用了Hibernate原生的session

@Repository

public class BaseDaoImpl<T> implements BaseDaoI<T> {

    @Autowired

    private SessionFactory sessionFactory;

    /**

     * 获得当前事物的session

     *

     * @return org.hibernate.Session

     */

    public Session getCurrentSession() {

return sessionFactory.getCurrentSession();

}

    @Override

    public T getByHql(String hql) {

Query q = getCurrentSession().createQuery(hql);

List<T> l = q.list();

if (l != null && l.size() > 0) {

    return l.get(0);

}

return null;

    }

    @Override

    public T getByHql(String hql, Map<String, Object> params) {

Query q = getCurrentSession().createQuery(hql);

if (params != null && !params.isEmpty()) {

    for (String key : params.keySet()) {

q.setParameter(key, params.get(key));

    }

}

List<T> l = q.list();

if (l != null && l.size() > 0) {

    return l.get(0);

}

return null;

    }

 @Override

    public Long count(String hql) {

Query q = getCurrentSession().createQuery(hql);

return (Long) q.uniqueResult();

    }

   @Override

    public List<Map> findBySql(String sql) {

SQLQuery q = getCurrentSession().createSQLQuery(sql);

return q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();

    }

BaseServiceImpl中有对泛型的处理:

@Service

public class BaseServiceImpl<T> implements BaseServiceI<T> {

    @Autowired

private BaseDaoI<T> baseDao;

   @Override

    public T getById(Serializable id) {

Class<T> c = (Class<T>) ((ParameterizedType) getClass()

.getGenericSuperclass()).getActualTypeArguments()[0];

return baseDao.getById(c, id);

    }

    @Override

    public T getByFilter(HqlFilter hqlFilter) {

String className = ((Class<T>) ((ParameterizedType) getClass()

.getGenericSuperclass()).getActualTypeArguments()[0]).getName();

String hql = "select distinct t from " + className + " t";

return getByHql(hql + hqlFilter.getWhereAndOrderHql(),

hqlFilter.getParams());

    }

 @Override

    public Long countByFilter(HqlFilter hqlFilter) {

String className = ((Class<T>) ((ParameterizedType) getClass()

.getGenericSuperclass()).getActualTypeArguments()[0]).getName();

String hql = "select count(distinct t) from " + className + " t";

return count(hql + hqlFilter.getWhereHql(), hqlFilter.getParams());

    }

这里有个自定义的HqlFilter用于添加where条件和排序,过滤结果集

 /**

     * 带参构造

     *

     * @param request

     */

    public HqlFilter(HttpServletRequest request) {

this.request = request;

addFilter(request);

}

    /**

     * 添加过滤

     *

     * @param request

     */

    public void addFilter(HttpServletRequest request) {

Enumeration<String> names = request.getParameterNames();

while (names.hasMoreElements()) {

    String name = names.nextElement();

    String value = request.getParameter(name);

    addFilter(name, value);

}

    }

    /**

     * 添加过滤

     *

     * 举例,name传递:QUERY_t#id_S_EQ

     *

     * 举例,value传递:0

     *

     * @param params

     */

    public void addFilter(String name, String value) {

if (name != null && value != null) {

    if (name.startsWith("QUERY_")) {// 如果有需要过滤的字段

String[] filterParams = StringUtils.split(name, "_");

if (filterParams.length == 4) {

    String columnName = filterParams[1].replaceAll("#", ".");// 要过滤的字段名称=t.id

    String columnType = filterParams[2];// 字段类型=S

    String operator = filterParams[3];// SQL操作符=EQ

    String placeholder = UUID.randomUUID().toString().replace("-", "");// 生成一个随机的参数名称

    if (hql.toString().indexOf(" where 1=1") < 0) {

hql.append("  where 1=1 ");

    }

    hql.append(" and " + columnName + " " + getSqlOperator(operator) + " :param"

    + placeholder + " ");// 拼HQL

    params.put("param" + placeholder, getObjValue(columnType, operator, value));// 添加参数

}

    }

}

    }

上面这个方法把 request里的参数全部映射,并且把 QUERY_t#id_S_EQ 拼成HQL

Where 1=1 and t.id =:paramXXX

然后准备好paramXXX的参数替换

其中操作符operator 是自定义的,包括EQ,NE,LK等,表示=,!=,like

参数替换时的columnType也是自定义的,包括S,I,D等,表示String,Integer,Date

String的时候如果是like,还要动态组合两边的 %

 /**

     * 获得添加过滤字段后加上排序字段的HQL

     *

     * @return

     */

    public String getWhereAndOrderHql() {

if (!StringUtils.isBlank(sort) && !StringUtils.isBlank(order)) {

    if (sort.indexOf(".") < 1) {

sort = "t." + sort;

    }

    hql.append(" order by " + sort + " " + order + " ");// 添加排序信息

} else {

    if (request != null) {

String s = request.getParameter("sort");

String o = request.getParameter("order");

if (!StringUtils.isBlank(s)) {

    sort = s;

}

if (!StringUtils.isBlank(o)) {

    order = o;

}

if (!StringUtils.isBlank(sort) && !StringUtils.isBlank(order)) {

    if (sort.indexOf(".") < 1) {

sort = "t." + sort;

    }

    hql.append(" order by " + sort + " " + order + " ");// 添加排序信息

}

    }

}

return hql.toString();

    }

这样就把Action里的参数完全转换成了HQL

SyuserServiceImpl中:

    @Override

    public void grantRole(String id, String roleIds) {

Syuser user = getById(id);

if (user != null) {

    user.setSyroles(new HashSet<Syrole>());

    for (String roleId : roleIds.split(",")) {

if (!StringUtils.isBlank(roleId)) {

    Syrole role = roleDao.getById(Syrole.class, roleId);

    if (role != null) {

user.getSyroles().add(role);

    }

}

    }

}

    }

    @Override

    public void grantOrganization(String id, String organizationIds) {

Syuser user = getById(id);

if (user != null) {

    user.setSyorganizations(new HashSet<Syorganization>());

    for (String organizationId : organizationIds.split(",")) {

if (!StringUtils.isBlank(organizationId)) {

    Syorganization organization = organizationDao.getById(

    Syorganization.class, organizationId);

    if (organization != null) {

user.getSyorganizations().add(organization);

    }

}

    }

}

    }

SyroleServiceImpl中:

  @Override

    public void saveRole(Syrole syrole, String userId) {

save(syrole);

Syuser user = userDao.getById(Syuser.class, userId);

user.getSyroles().add(syrole);// 把新添加的角色与当前用户关联

    }

SyorganizationServiceImpl中:

 @Override

    public void saveOrganization(Syorganization syorganization, String userId) {

save(syorganization);

Syuser user = userDao.getById(Syuser.class, userId);

user.getSyorganizations().add(syorganization);

    }

Model中:

Syuser

    @ManyToMany(fetch = FetchType.LAZY)

    @JoinTable(name = "SYUSER_SYORGANIZATION", schema = "", joinColumns = { @JoinColumn(name = "SYUSER_ID", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "SYORGANIZATION_ID", nullable = false, updatable = false) })

    public Set<Syorganization> getSyorganizations() {

return this.syorganizations;

    }

    public void setSyorganizations(Set<Syorganization> syorganizations) {

this.syorganizations = syorganizations;

    }

    @ManyToMany(fetch = FetchType.LAZY)

    @JoinTable(name = "SYUSER_SYROLE", schema = "", joinColumns = { @JoinColumn(name = "SYUSER_ID", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "SYROLE_ID", nullable = false, updatable = false) })

    public Set<Syrole> getSyroles() {

return this.syroles;

    }

    public void setSyroles(Set<Syrole> syroles) {

this.syroles = syroles;

    }

Syrole

    @ManyToMany(fetch = FetchType.LAZY)

    @JoinTable(name = "SYUSER_SYROLE", schema = "", joinColumns = { @JoinColumn(name = "SYROLE_ID", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "SYUSER_ID", nullable = false, updatable = false) })

    public Set<Syuser> getSyusers() {

return this.syusers;

    }

    public void setSyusers(Set<Syuser> syusers) {

this.syusers = syusers;

    }

Syorganization

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "syorganization", cascade = CascadeType.ALL)

    public Set<Syorganization> getSyorganizations() {

return this.syorganizations;

    }

    public void setSyorganizations(Set<Syorganization> syorganizations) {

this.syorganizations = syorganizations;

    }

    @ManyToMany(fetch = FetchType.LAZY)

    @JoinTable(name = "SYUSER_SYORGANIZATION", schema = "", joinColumns = { @JoinColumn(name = "SYORGANIZATION_ID", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "SYUSER_ID", nullable = false, updatable = false) })

    public Set<Syuser> getSyusers() {

return this.syusers;

    }

    public void setSyusers(Set<Syuser> syusers) {

this.syusers = syusers;

    }

这样,权限相关的后台部分就结束了,效果如下:

1.点击登陆,会首先获取菜单((SyresourceServiceI) service).getMainMenu(

wpsEAEB.tmp 

先查角色的:

select distinct t from Syresource t join t.syroles role join role.syusers user  where 1=1  and user.id  =  :param49bd757c16594cbe8657b7d88364d81a  and t.syresourcetype.id  =  :paramf778a1257fa64e9ebca2a52bcc9750fc

再查组织的:

select distinct t from Syresource t join t.syorganizations organization join organization.syusers user  where 1=1  and user.id  =  :param49bd757c16594cbe8657b7d88364d81a  and t.syresourcetype.id  =  :paramf778a1257fa64e9ebca2a52bcc9750fc

2.点击用户管理菜单,会通过SecurityUtil查询权限,并动态显示某些功能图标

因为登陆时已经对该用户所有资源都强制加载了,这时候不再查数据库

也就是每次更改了权限后需要重新登陆

3.点击某个用户的用户角色:

wpsEAFC.tmp 

首先调用user.getSyroles()得到当前用户所有角色:当然这里是错的,应该跟用户无关,查询所有角色

Initializing collection [sy.model.base.Syuser.syroles#0]

SELECT

syroles0_.SYUSER_ID AS SYUSER1_7_1_,

syroles0_.SYROLE_ID AS SYROLE2_9_1_,

syrole1_.ID AS ID1_5_0_,

syrole1_.CREATEDATETIME AS CREATEDA2_5_0_,

syrole1_.DESCRIPTION AS DESCRIPT3_5_0_,

syrole1_.ICONCLS AS ICONCLS4_5_0_,

syrole1_. NAME AS NAME5_5_0_,

syrole1_.SEQ AS SEQ6_5_0_,

syrole1_.UPDATEDATETIME AS UPDATEDA7_5_0_

FROM

SYUSER_SYROLE syroles0_

INNER JOIN SYROLE syrole1_ ON syroles0_.SYROLE_ID = syrole1_.ID

WHERE

syroles0_.SYUSER_ID = '0'

Collection initialized

这里为什么又查一遍数据库??

登陆时不是全都初始化过了??

然后得到所选用户的所有角色,并在页面上勾选:

wpsEAFD.tmp 

select distinct t from Syrole t join t.syusers user  where 1=1  and user.id  =  :paramdac50de702204cc6a258b8af78905a65

另外虽然数据库中的多对多并没有方向性,但页面上并不提供双向查询

这里的顺序是:用户->角色/组织->资源

通过后台可以发现,Hibernate总是有不必要的Sql执行,实际项目中肯定要最后优化一遍

http://www.cnblogs.com/gcg0036/p/4393526.html