SpringAop之靜態代理AspectJ
阿新 • • 發佈:2020-12-20
最近一段時間,用到了SpringAop 裡的AspectJ 靜態代理面向切面程式設計,感覺開發效率提升不少,今天特意總結一下,防止以後遺忘。
首先,總體複習一下Aop的相關知識
-
總體結構圖
-
Aop 應用場景
Authentication 許可權、Caching 快取、Context passing 內容傳遞、Error handling 錯誤處理、Lazy loading 懶載入、Debugging 除錯、logging,tracing,profiling and monitoring 記錄跟蹤 優化 校準、Performance optimization 效能優化、Persistence 持久化、Persistence 持久化、Resource pooling 資源池、Synchronization 同步、Transactions 事務、Logging 日誌 -
專案例項
例項簡介:
通過AspectJ 在SpingBoot2+mybatis3+vue3 框架下 通過註解,切入到serviceImpl 方法級別上,動態新增引數實現sql的動態注入。
專案背景
省級下邊不同的市級使用者登陸後,根據該使用者屬於不同 市代號(AreaCode)來實現只能檢視屬於該區域的資料。體現在Mybatis裡的xml 動態注入sql
配置步驟:
(1)配置AreaScopeAOP
package com.dechnic.omsdc.server.admin.aop;
import com.dechnic.omsdc.server.admin.config.Config;
import com.dechnic.omsdc.server.admin.entity.BaseEntity;
import com.dechnic.omsdc.server.admin.entity.TSysPerm;
import com.dechnic.omsdc.server.admin.entity.TSysRole;
import com.dechnic.omsdc.server.admin.entity.TSysUser;
import com.dechnic.omsdc.server.admin.service.TSysRoleService;
import com.dechnic. omsdc.server.common.annotation.AreaScope;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
@Aspect
public class AreaScopeAOP {
public static final String AREA = "area"; // 區域
public static final String AREA_ForReport = "areaForReport"; // 查詢報表用
public static final String AREA_SCOPE = "areaScope";
@Autowired
private TSysRoleService roleService;
@Pointcut("@annotation(com.dechnic.omsdc.server.common.annotation.AreaScope)")
public void dataScopePointCut() {}
@Before("dataScopePointCut()")
public void beforePointCut(JoinPoint jp) throws Throwable {
TSysUser user = (TSysUser) SecurityUtils.getSubject().getPrincipal();
if (user.isAdmin()) {
return;
}
// 獲得註解
AreaScope areaScope = getAnnotationLog(jp);
if (AREA.equals(areaScope.type())){
this.handleAreaDataScope(jp,areaScope.tableAlias(),areaScope.tableColumn());
}else if (AREA_ForReport.equals(areaScope.type())){
this.handleAreaDataScopeForReport(jp,areaScope.tableAlias(),areaScope.tableColumn());
}
}
private void handleAreaDataScope(JoinPoint jp,String alias,String col) throws Exception {
TSysUser user = (TSysUser) SecurityUtils.getSubject().getPrincipal();
if (user == null){
log.info("areaScopeAOP========================user 為null");
}else{
List<TSysRole> roleList = user.getRoleList();
if (roleList == null || roleList.size() == 0) {
roleList = roleService.getUserRoleInfo(user.getId(), TSysPerm.PERM_TYPE.MENU);
if(roleList == null || roleList.size()==0){
throw new AuthenticationException(user.getUserName()+"尚未分配角色,請聯絡管理員!");
}
user.setRoleList(roleList);
}
}
Object obj = jp.getArgs()[0];
// BaseEntity entity = (BaseEntity) jp.getArgs()[0];
for (TSysRole role : user.getRoleList()) {
if (TSysRole.PERM_TYPE.ALL.equals(role.getDeptPermType())) {
return;
}
}
if (Config.provinceCode.equals(user.getAreaCode())){// 省使用者不做校驗
return;
}
String aliasCond = "";
if (!StringUtils.isNotEmpty(col)){
throw new Exception("區域資料許可權註解,區域area_code列名不能為空!");
}
if (StringUtils.isNotEmpty(alias)){
aliasCond = alias + "." ;
}
if (obj instanceof Map){
Map map = (Map) obj;
String sql = String.format(
"and %s%s ='%s' AND %sF_BuildGroupID in (" +
"SELECT p.resource_id from t_sys_perm p INNER JOIN " +
"t_sys_role_perm rp on p.id = rp.perm_id " +
"INNER JOIN t_sys_role r on rp.role_id = r.id " +
"INNER JOIN t_sys_user_role ur ON r.id = ur.role_id " +
"INNER JOIN t_sys_user u ON ur.user_id = u.id " +
"AND u.id ='%s' " +
"AND p.perm_type='CORP')",
aliasCond,col,user.getAreaCode(),aliasCond,user.getId());
map.put(AREA_SCOPE,sql);
}else {
BaseEntity entity = (BaseEntity) obj;
String sql = String.format(
"and %s%s ='%s' AND %sF_BuildGroupID in (" +
"SELECT p.resource_id from t_sys_perm p INNER JOIN " +
"t_sys_role_perm rp on p.id = rp.perm_id " +
"INNER JOIN t_sys_role r on rp.role_id = r.id " +
"INNER JOIN t_sys_user_role ur ON r.id = ur.role_id " +
"INNER JOIN t_sys_user u ON ur.user_id = u.id " +
"AND u.id ='%s' " +
"AND p.perm_type='CORP')",
aliasCond,col,user.getAreaCode(),aliasCond,user.getId());
entity.getParams().put(AREA_SCOPE,sql);
}
/*if (obj instanceof Map){
Map map = (Map) obj;
String sql = String.format(
"and %s%s ='%s'",
aliasCond,col,user.getAreaCode());
map.put(AREA_SCOPE,sql);
}else {
BaseEntity entity = (BaseEntity) obj;
String sql = null;
sql = String.format(
"and %s%s ='%s'",
aliasCond,col,user.getAreaCode());
entity.getParams().put(AREA_SCOPE,sql);
}*/
}
private void handleAreaDataScopeForReport(JoinPoint jp,String alias,String col) throws Exception {
TSysUser user = (TSysUser) SecurityUtils.getSubject().getPrincipal();
if (user == null){
log.info("areaScopeAOP========================user 為null");
}else{
List<TSysRole> roleList = user.getRoleList();
if (roleList == null || roleList.size() == 0) {
roleList = roleService.getUserRoleInfo(user.getId(), TSysPerm.PERM_TYPE.MENU);
if(roleList == null || roleList.size()==0){
throw new AuthenticationException(user.getUserName()+"尚未分配角色,請聯絡管理員!");
}
user.setRoleList(roleList);
}
}
// BaseEntity entity = (BaseEntity) jp.getArgs()[0];
for (TSysRole role : user.getRoleList()) {
if (TSysRole.PERM_TYPE.ALL.equals(role.getDeptPermType())) {
return;
}
}
if (Config.provinceCode.equals(user.getAreaCode())){// 省使用者不做校驗
return;
}
Object obj = jp.getArgs()[0];
if (obj instanceof Map){
Map map = (Map) obj;
map.put("areaCode",user.getAreaCode());
}
}
/** 是否存在註解,如果存在就獲取 */
private AreaScope getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(AreaScope.class);
}
return null;
}
}
(2)配置註解annotation
package com.dechnic.omsdc.server.common.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AreaScope {
public String type() default "area";
public String tableAlias() default "";
public String tableColumn() default "area_code";
}
(3).在方法上使用註解
package com.dechnic.omsdc.server.common.service.impl;
import com.dechnic.omsdc.server.common.annotation.AreaScope;
import com.dechnic.omsdc.server.common.annotation.DataScope;
import com.dechnic.omsdc.server.common.entity.VBuildGroupInfo;
import com.dechnic.omsdc.server.common.mapper.VBuildGroupInfoMapper;
import com.dechnic.omsdc.server.common.service.IVBuildGroupInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class VBuildGroupInfoServiceImpl implements IVBuildGroupInfoService {
@Autowired
VBuildGroupInfoMapper vBuildGroupInfoMapper;
@Override
@AreaScope(tableAlias = "g")
@DataScope(type = "corp",tableAlias = "g",tableColumn = "F_BuildGroupID")
public List<VBuildGroupInfo> selectByMap(Map<String, Object> map) {
return vBuildGroupInfoMapper.selectByMap(map);
}
}
(4)在mybatis 的xml 方法裡新增${areaScope}
<select id="selectByMap" parameterType="map" resultMap="BaseResultMap">
SELECT
g.*, d.F_Name AS fBuildFuncName
FROM
V_BuildGroupInfo g
inner JOIN (
SELECT
*
FROM
T_BD_ReferDict
WHERE
F_Type = 'BFunc'
) d ON g.F_BuildGroupFunc = d.F_code
${areaScope}
<if test="fBuildgroupname !=null and fBuildgroupname !=''">
and g.F_BuildGroupName like '%'+#{fBuildgroupname}+'%'
</if>
<if test="groupIds != null">
and g.F_BuildGroupID in
<foreach collection="groupIds" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</if>
${dataScope}
<!--<if test="fBuildfunc != null and fBuildfunc.size()>0">-->
<!--and ( 1!=1-->
<!--<foreach collection="fBuildfunc" item="item" index="index">-->
<!--or b.F_BuildFunc = #{item}-->
<!--</foreach>-->
<!--)-->
<!--</if>-->
</select>