web開發(fā)中的權(quán)限設(shè)計(jì)拙見一二(3) ----資源配置與權(quán)限判斷
Posted on 2007-01-03 13:56 江上一葉舟 閱讀(3636) 評論(15) 編輯 收藏 所屬分類: 軟件藝術(shù)在上文中我們提到了一個(gè)資源對應(yīng)一個(gè)數(shù)據(jù)庫表,在T_ResourceInfo表中我們也提到了有一個(gè)字段專門來記錄表名,然后我書寫一個(gè)資源配置文件,用來配置我的業(yè)務(wù)類與資源的對應(yīng)關(guān)系,代碼如下:
用戶登錄后,需要操作T_UserInfo這個(gè)表時(shí),我們的邏輯將會把請求帶入IBLogin這個(gè)業(yè)務(wù)邏輯中,在我們的AOP模塊中,可以用MethodInterceptor來截獲當(dāng)前用戶想要操作的業(yè)務(wù)邏輯,當(dāng)AOP模塊截獲了用戶的請求,并判斷用戶想要操作IBLogin這個(gè)業(yè)務(wù)邏輯,它將在上述的mapping文件中去找該業(yè)務(wù)邏輯對應(yīng)的資源user_info,然后去資源表中判斷該用戶是否有操作user_info的權(quán)限。
(注:上述xml文件在系統(tǒng)初始化時(shí)候加載入內(nèi)存中,我們也可以將權(quán)限信息也加載在內(nèi)存中,不會很大,一切資源在內(nèi)存中操作,非常快)
下面我貼點(diǎn)代碼,在系統(tǒng)初始化時(shí):
下面是AOP模塊的advice代碼:
package?com.ideal.framework.sys.advice;


/**?*//**
?*?<p>Title:?BusinessAccessAdvisor</p>
?*?<p>Description:?業(yè)務(wù)模塊AOP權(quán)限監(jiān)聽器</p>
?*?<p>Copyright:?Copyright?(c)?2006</p>
?*?<p>Company:?ideal</p>
?*?@author?alex
?*?@version?1.0
?*/

import?org.aopalliance.intercept.MethodInterceptor;
import?org.aopalliance.intercept.MethodInvocation;
import?com.ideal.framework.InitResource;
import?com.ideal.framework.util.XMLUtil;
import?java.util.ArrayList;
import?java.util.Hashtable;
import?com.ideal.framework.sys.accesscontrol.GenericAccessBase;
import?java.lang.reflect.Field;
import?com.ideal.framework.po.*;
import?java.lang.reflect.Method;
import?java.util.*;
import?java.io.*;
import?javax.servlet.http.HttpServletRequest;

public?class?BusinessAccessAdvisor
????implements?MethodInterceptor

{

????public?BusinessAccessAdvisor()

????{
????}

????public?Object?invoke(MethodInvocation?invocation)?throws
????????Throwable

????{
????????String?user_name?=?"";
????????Object?obj?=?invocation.getArguments()[1];
????????if?(obj?instanceof?HttpServletRequest)

????{
????????????HttpServletRequest?request?=?(HttpServletRequest)obj;
????????????user_name?=?(String)request.getSession().getAttribute("UserName");//取出用戶名
????????}
????????String?bean_name?=?invocation.getMethod().getDeclaringClass().getName();//取出用戶想要操作的業(yè)務(wù)邏輯
????????XMLUtil?xml?=?(XMLUtil)?InitResource.context.getBean("XMLUtil");
????????ArrayList?list?=?xml.getFieldList("mapping",?"s",?xml.doc);
????????for?(int?i?=?0;?i?<?list.size();?i++)

????{
????????????Hashtable?hash?=?(Hashtable)?list.get(i);
????????????if?(hash.get("BusinessClass").equals(invocation.getMethod().//判斷用戶是否有權(quán)操作該業(yè)務(wù)邏輯所對應(yīng)表
?????????????????????????????????????????????????getDeclaringClass().getName()))

????????{
????????????????String?table_name?=?(String)?hash.get("TableName");
????????????????GenericAccessBase?access_controller?=?(GenericAccessBase)
????????????????????InitResource.context.getBean("GenericAccessBase");
????????????????if?(access_controller.CheckAccessPrivilege(user_name,?table_name))//若用戶有權(quán)操作該表,則讓程序進(jìn)入業(yè)務(wù)邏輯

????????????{
????????????????????return?invocation.proceed();
????????????????}
????????????}
????????}
????????System.out.println("no?permission?.reject?by?"?+?bean_name);
????????return?null;
????}
}
下面是判斷用戶是否具有操作該表權(quán)限的類:
貼一個(gè)privilege標(biāo)簽的代碼:
如此,系統(tǒng)會自動根據(jù)當(dāng)前session中的用戶來判斷是否需要顯示當(dāng)前的添加按鈕。
到此所有權(quán)限的代碼完成,在此套權(quán)限設(shè)計(jì)中,我始終抱著AOP的想法:讓他屬于一個(gè)系統(tǒng)切面,以后再開發(fā)其他系統(tǒng)時(shí),作為一個(gè)模塊就可以加載上去,與系統(tǒng)無關(guān)
1
<?xml?version="1.0"?encoding="GB2312"?>
2
<data>
3
????<mapping?SysName="s">
4
????????<module?BusinessClass="com.ideal.framework.business.businessface.IBLogin"?TableName="user_info"/>
5
????</mapping>
6
</data>
其中BusinessClass代表業(yè)務(wù)接口,TableName代表該業(yè)務(wù)接口所要操作的數(shù)據(jù)實(shí)體(數(shù)據(jù)表),此處的TableName必須與T_ResourceInfo中的Module_Code一致。
2

3

4

5

6

用戶登錄后,需要操作T_UserInfo這個(gè)表時(shí),我們的邏輯將會把請求帶入IBLogin這個(gè)業(yè)務(wù)邏輯中,在我們的AOP模塊中,可以用MethodInterceptor來截獲當(dāng)前用戶想要操作的業(yè)務(wù)邏輯,當(dāng)AOP模塊截獲了用戶的請求,并判斷用戶想要操作IBLogin這個(gè)業(yè)務(wù)邏輯,它將在上述的mapping文件中去找該業(yè)務(wù)邏輯對應(yīng)的資源user_info,然后去資源表中判斷該用戶是否有操作user_info的權(quán)限。
(注:上述xml文件在系統(tǒng)初始化時(shí)候加載入內(nèi)存中,我們也可以將權(quán)限信息也加載在內(nèi)存中,不會很大,一切資源在內(nèi)存中操作,非常快)
下面我貼點(diǎn)代碼,在系統(tǒng)初始化時(shí):
?1
package?com.ideal.framework;
?2
?3
import?java.util.*;
?4
import?java.sql.*;
?5
import?com.ideal.framework.dao.daoface.*;
?6
import?com.ideal.framework.po.*;
?7
?8
public?class?ResourceContainer
?9
{
10
????public?static?boolean?change_resource;?//更新資源??系統(tǒng)持久
11
????public?static?Vector?resource_container?=?new?Vector();?//資源容器??用戶持久
12
????private?IUserRoleDAO?m_user_role_dao;
13
????private?IRoleResourceDAO?m_role_resource_dao;
14
????private?IUserDAO?m_user_dao;
15
16
????public?ResourceContainer()
17
{
18
????}
19
20
????public?void?setUserResource()
21
????{
22
????????System.out.println("initialize?resource:");
23
????????List?user_list?=?m_user_dao.getAllUser();
24
????????for?(int?i?=?0;?i?<?user_list.size();?i++)
25
????????{
26
????????????UserInfo?user?=?(UserInfo)?user_list.get(i);
27
????????????List?role_list?=?m_user_role_dao.getRoleInfo(user);
28
????????????for?(int?j?=?0;?j?<?role_list.size();?j++)
29
????????????{
30
????????????????RoleInfo?role?=?(RoleInfo)?role_list.get(j);
31
????????????????List?resource_list?=?m_role_resource_dao.
32
????????????????????getResourceInfo(role);
33
????????????????for?(int?k?=?0;?k?<?resource_list.size();?k++)
34
????????????????{
35
????????????????????Hashtable?hash?=?new?Hashtable();
36
????????????????????hash.put(user.getLoginId(),?resource_list.get(k));
37
????????????????????hash.put("Unit_"+user.getLoginId(),?user.getUnit());
38
????????????????????hash.put("Role_"+user.getLoginId(),?role.getRoleName());
39
????????????????????ResourceContainer.resource_container.add(hash);
40
????????????????}
41
????????????}
42
????????}
43
????}
44
45
????public?Vector?getResource_container()
46
????{
47
????????return?resource_container;
48
????}
49
50
????public?void?setResource_container(Vector?resource_container)
51
????{
52
????????this.resource_container?=?resource_container;
53
????}
54
55
????public?IRoleResourceDAO?getM_role_resource_dao()
56
????{
57
????????return?m_role_resource_dao;
58
????}
59
60
????public?IUserDAO?getM_user_dao()
61
????{
62
????????return?m_user_dao;
63
????}
64
65
????public?IUserRoleDAO?getM_user_role_dao()
66
????{
67
????????return?m_user_role_dao;
68
????}
69
70
????public?void?setM_role_resource_dao(IRoleResourceDAO?m_role_resource_dao)
71
????{
72
????????this.m_role_resource_dao?=?m_role_resource_dao;
73
????}
74
75
????public?void?setM_user_dao(IUserDAO?m_user_dao)
76
????{
77
????????this.m_user_dao?=?m_user_dao;
78
????}
79
80
????public?void?setM_user_role_dao(IUserRoleDAO?m_user_role_dao)
81
????{
82
????????this.m_user_role_dao?=?m_user_role_dao;
83
????}
84
85
????public?void?setChange_resource(boolean?change_resource)
86
????{
87
????????this.change_resource?=?change_resource;
88
????}
89
90
????public?boolean?isChange_resource()
91
????{
92
????????return?change_resource;
93
????}
94
}
95
將用戶對應(yīng)的角色,資源信息加載如內(nèi)存,另外在初始化時(shí)候的xml文件的樹形結(jié)構(gòu)也加載入內(nèi)存,這邊就不貼代碼了
?2

?3

?4

?5

?6

?7

?8

?9


10

11

12

13

14

15

16

17


18

19

20

21


22

23

24

25


26

27

28

29


30

31

32

33

34


35

36

37

38

39

40

41

42

43

44

45

46


47

48

49

50

51


52

53

54

55

56


57

58

59

60

61


62

63

64

65

66


67

68

69

70

71


72

73

74

75

76


77

78

79

80

81


82

83

84

85

86


87

88

89

90

91


92

93

94

95

下面是AOP模塊的advice代碼:










































































?1
package?com.ideal.framework.sys.accesscontrol;
?2
?3
import?com.ideal.framework.InitResource;
?4
import?com.ideal.framework.util.XMLUtil;
?5
import?com.ideal.framework.po.UserInfo;
?6
import?com.ideal.framework.ResourceContainer;
?7
import?java.util.*;
?8
//import?com.ideal.framework.po.ResourceInfo;
?9
10
public?class?GenericAccessBase
11
{
12
????UserInfo?user;
13
14
????public?GenericAccessBase()
15
????{
16
????}
17
18
????public?void?setUser(UserInfo?user)
19
????{
20
????????this.user?=?user;
21
????}
22
23
????public?boolean?CheckAccessPrivilege(String?user_name,?String?table_name)
24
????{
25
????????for?(int?i?=?0;?i?<?ResourceContainer.resource_container.size();?i++)
26
????????{
27
????????????Hashtable?temp_hash?=?(Hashtable)ResourceContainer.resource_container.get(i);//從內(nèi)存中取出用戶資源信息
28
????????????if?(temp_hash.containsKey(user_name))
29
????????????{
30
????????????????ResourceInfo?resource?=?(ResourceInfo)temp_hash.get(user_name);
31
????????????????if?(table_name.trim().toLowerCase().equals(resource.getModuleCode().trim().toLowerCase()))//比對用戶擁有的資源和當(dāng)前的table_name
32
????????????????{
33
????????????????????return?true;
34
????????????????}
35
????????????}
36
????????}
37
????????return?false;
38
????}
39
}
40
ok,到此為止,我們的底層攔截就完成了,接下來就是界面權(quán)限處理,界面權(quán)限比較復(fù)雜,因?yàn)橛脩艨赡芫哂刑砑訖?quán)限,沒有上傳權(quán)限,有下載權(quán)限卻沒有更新權(quán)限等,情況很復(fù)雜,所以我們這邊必須有一個(gè)判斷當(dāng)前用戶是否具有這些復(fù)雜權(quán)限的類:
?2

?3

?4

?5

?6

?7

?8

?9

10

11


12

13

14

15


16

17

18

19


20

21

22

23

24


25

26


27

28

29


30

31

32


33

34

35

36

37

38

39

40

??1
package?com.ideal.framework.sys.privilege;
??2
??3
/**?*//**
??4
?*?<p>Title:?GenericPrivilegeBase</p>
??5
?*?<p>Description:?通用權(quán)限法則</p>
??6
?*?<p>Copyright:?Copyright?(c)?2006</p>
??7
?*?<p>Company:?ideal</p>
??8
?*?@author?alex
??9
?*?@version?1.0
?10
?*/
?11
?12
public?class?GenericPrivilegeBase
?13

{
?14
????public?final?static?int?NO_PRIVILEGE?=?0;
?15
????public?final?static?int?QUERY_OR_USE_PRIVILEGE?=?1;//察看權(quán)限
?16
????public?final?static?int?CREATE_PRIVILEGE?=?2;//添加權(quán)限
?17
????public?final?static?int?DELETE_PRIVILEGE?=?4;//刪除權(quán)限
?18
????public?final?static?int?UPDATE_PRIVILEGE?=?8;//更新權(quán)限
?19
????public?final?static?int?ALL_PRIVILEGE?=?QUERY_OR_USE_PRIVILEGE?|
?20
????????CREATE_PRIVILEGE?|?DELETE_PRIVILEGE?|?UPDATE_PRIVILEGE;//增刪改查權(quán)限
?21
?22
????public?GenericPrivilegeBase()
?23
????
{
?24
????}
?25
?26
????public?static?boolean?isValidPrivilege(int?privilege)//判斷是否具有權(quán)限
?27
????
{
?28
????????if?(?(privilege?&?QUERY_OR_USE_PRIVILEGE)?!=?0)
?29
????????
{
?30
????????????return?true;
?31
????????}
?32
?33
????????if?(?(privilege?&?CREATE_PRIVILEGE)?!=?0)
?34
????????
{
?35
????????????return?true;
?36
????????}
?37
?38
????????if?(?(privilege?&?DELETE_PRIVILEGE)?!=?0)
?39
????????
{
?40
????????????return?true;
?41
????????}
?42
?43
????????if?(?(privilege?&?UPDATE_PRIVILEGE)?!=?0)
?44
????????
{
?45
????????????return?true;
?46
????????}
?47
?48
????????return?false;
?49
????}
?50
?51
????public?static?boolean?checkQueryPrivilege(int?privilege)//判斷是否具有察看權(quán)限
?52
????
{
?53
????????if?(?(privilege?&?QUERY_OR_USE_PRIVILEGE)?!=?0)
?54
????????
{
?55
????????????return?true;
?56
????????}
?57
????????else
?58
????????
{
?59
????????????return?false;
?60
????????}
?61
????}
?62
?63
????public?static?boolean?checkUsePrivilege(int?privilege)
?64
????
{
?65
????????if?(?(privilege?&?QUERY_OR_USE_PRIVILEGE)?!=?0)
?66
????????
{
?67
????????????return?true;
?68
????????}
?69
????????else
?70
????????
{
?71
????????????return?false;
?72
????????}
?73
????}
?74
?75
????public?static?boolean?checkCreatePrivilege(int?privilege)//判斷是否有添加權(quán)限
?76
????
{
?77
????????if?(?(privilege?&?CREATE_PRIVILEGE)?!=?0)
?78
????????
{
?79
????????????return?true;
?80
????????}
?81
????????else
?82
????????
{
?83
????????????return?false;
?84
????????}
?85
????}
?86
?87
????public?static?boolean?checkDeletePrivilege(int?privilege)//判斷是否有刪除權(quán)限
?88
????
{
?89
????????if?(?(privilege?&?DELETE_PRIVILEGE)?!=?0)
?90
????????
{
?91
????????????return?true;
?92
????????}
?93
????????else
?94
????????
{
?95
????????????return?false;
?96
????????}
?97
????}
?98
?99
????public?static?boolean?checkUpdatePrivilege(int?privilege)
100
????
{
101
????????if?(?(privilege?&?UPDATE_PRIVILEGE)?!=?0)
102
????????
{
103
????????????return?true;
104
????????}
105
????????else
106
????????
{
107
????????????return?false;
108
????????}
109
????}
110
}
111
然后我們自定義兩個(gè)標(biāo)簽,Privilege與noPrivilege用來判斷用戶是否具有權(quán)限,這兩個(gè)標(biāo)簽必須具有三個(gè)基本的attribute,beanName:當(dāng)前所要操作的哪個(gè)資源;scope:用戶信息存放在哪個(gè)域;operation:用戶想要進(jìn)行什么操作
??2

??3


??4

??5

??6

??7

??8

??9

?10

?11

?12

?13



?14

?15

?16

?17

?18

?19

?20

?21

?22

?23



?24

?25

?26

?27



?28

?29



?30

?31

?32

?33

?34



?35

?36

?37

?38

?39



?40

?41

?42

?43

?44



?45

?46

?47

?48

?49

?50

?51

?52



?53

?54



?55

?56

?57

?58



?59

?60

?61

?62

?63

?64



?65

?66



?67

?68

?69

?70



?71

?72

?73

?74

?75

?76



?77

?78



?79

?80

?81

?82



?83

?84

?85

?86

?87

?88



?89

?90



?91

?92

?93

?94



?95

?96

?97

?98

?99

100



101

102



103

104

105

106



107

108

109

110

111

貼一個(gè)privilege標(biāo)簽的代碼:
??1
package?com.ideal.framework.tag;
??2
??3
import?javax.servlet.jsp.tagext.BodyTagSupport;
??4
import?javax.servlet.jsp.tagext.*;
??5
import?javax.servlet.http.*;
??6
import?javax.servlet.jsp.*;
??7
import?java.sql.*;
??8
import?java.io.*;
??9
import?com.ideal.framework.*;
?10
import?com.ideal.framework.po.ResourceInfo;
?11
import?java.util.Hashtable;
?12
import?com.ideal.framework.sys.privilege.GenericPrivilegeBase;
?13
?14
public?class?PrivilegeTag
?15
????extends?BodyTagSupport
?16

{
?17
????String?operation;
?18
????private?String?beanName;
?19
????private?String?scope;
?20
?21
????public?PrivilegeTag()
?22
????
{
?23
????????super();
?24
????}
?25
?26
????public?void?setOperation(String?operation)
?27
????
{
?28
????????this.operation?=?operation;
?29
????}
?30
?31
????public?void?setBeanName(String?beanName)
?32
????
{
?33
????????this.beanName?=?beanName;
?34
????}
?35
?36
????public?void?setScope(String?scope)
?37
????
{
?38
????????this.scope?=?scope;
?39
????}
?40
?41
????public?int?doStartTag()?throws?JspTagException
?42
????
{
?43
????????if?(scope?==?null?||?scope.equals(""))
?44
????????????return?SKIP_BODY;
?45
????????else
?46
????????
{
?47
????????????String?user_name?=?"";
?48
????????????if?(scope.equalsIgnoreCase("session"))
?49
????????????
{
?50
????????????????HttpSession?session?=?pageContext.getSession();
?51
????????????????user_name?=?(String)?session.getAttribute("UserName");
?52
????????????}
?53
????????????else
?54
????????????
{
?55
????????????????HttpServletRequest?request?=?(HttpServletRequest)?pageContext.
?56
????????????????????getRequest();
?57
????????????????user_name?=?(String)?request.getAttribute("UserName");
?58
????????????}
?59
?60
????????????for?(int?i?=?0;?i?<?ResourceContainer.resource_container.size();?i++)
?61
????????????
{
?62
????????????????Hashtable?temp_hash?=?(Hashtable)?ResourceContainer.
?63
????????????????????resource_container.get(i);
?64
????????????????if?(temp_hash.containsKey(user_name))
?65
????????????????
{
?66
????????????????????ResourceInfo?resource?=?(ResourceInfo)?temp_hash.get(
?67
????????????????????????user_name);
?68
????????????????????if?(beanName.trim().toLowerCase().equals(resource.
?69
????????????????????????getModuleCode().trim().toLowerCase()))
?70
????????????????????
{
?71
????????????????????????if(this.checkPrivilege(resource.getPrivilegeCode())?==?EVAL_BODY_TAG)
?72
????????????????????????????return?EVAL_BODY_TAG;
?73
????????????????????}
?74
????????????????}
?75
????????????}
?76
?77
????????}
?78
????????return?SKIP_BODY;
?79
return?EVAL_BODY_TAG;
?80
????}
?81
?82
????public?int?checkPrivilege(String?privilege)
?83
????
{
?84
????????int?int_privilege?=?0;
?85
????????try
?86
????????
{
?87
????????????int_privilege?=?Integer.parseInt(privilege);
?88
????????}
?89
????????catch?(NumberFormatException?ex)
?90
????????
{
?91
????????????System.out.println(ex.getMessage());
?92
????????}
?93
????????GenericPrivilegeBase?gpb?=?new?GenericPrivilegeBase();
?94
????????if?(operation.equals("NONE"))
?95
????????????return?EVAL_BODY_TAG;
?96
????????if?(operation.equals("QUERY"))
?97
????????????if?(gpb.checkQueryPrivilege(int_privilege))
?98
????????????????return?EVAL_BODY_TAG;
?99
????????if?(operation.equals("CREATE"))
100
????????????if?(gpb.checkCreatePrivilege(int_privilege))
101
????????????????return?EVAL_BODY_TAG;
102
????????if?(operation.equals("DELETE"))
103
????????????if?(gpb.checkDeletePrivilege(int_privilege))
104
????????????????return?EVAL_BODY_TAG;
105
????????if?(operation.equals("UPDATE"))
106
????????????if?(gpb.checkUpdatePrivilege(int_privilege))
107
????????????????return?EVAL_BODY_TAG;
108
????????if?(operation.equals("USE"))
109
????????????if?(gpb.checkUsePrivilege(int_privilege))
110
????????????????return?EVAL_BODY_TAG;
111
????????return?SKIP_BODY;
112
????}
113
114
????public?int?doAfterBody()?throws?JspTagException
115
????
{
116
????????return?SKIP_BODY;
117
????}
118
119
????public?int?doEndTag()?throws?JspTagException
120
????
{
121
????????try
122
????????
{
123
????????????if?(bodyContent?!=?null)
124
????????????
{
125
????????????????bodyContent.writeOut(bodyContent.getEnclosingWriter());
126
????????????}
127
????????}
128
????????catch?(IOException?ex)
129
????????
{
130
????????????throw?new?JspTagException("IO?Error:"?+?ex.getMessage());
131
????????}
132
????????return?EVAL_PAGE;
133
????}
134
135
????public?void?doInitBody()?throws?JspTagException
136
????
{
137
????}
138
139
????public?void?setBodyContent(BodyContent?bodyContent)
140
????
{
141
????????this.bodyContent?=?bodyContent;
142
????}
143
}
144
在頁面上,我們?nèi)绱耸褂迷摌?biāo)簽:
??2

??3

??4

??5

??6

??7

??8

??9

?10

?11

?12

?13

?14

?15

?16



?17

?18

?19

?20

?21

?22



?23

?24

?25

?26

?27



?28

?29

?30

?31

?32



?33

?34

?35

?36

?37



?38

?39

?40

?41

?42



?43

?44

?45

?46



?47

?48

?49



?50

?51

?52

?53

?54



?55

?56

?57

?58

?59

?60

?61



?62

?63

?64

?65



?66

?67

?68

?69

?70



?71

?72

?73

?74

?75

?76

?77

?78

?79

?80

?81

?82

?83



?84

?85

?86



?87

?88

?89

?90



?91

?92

?93

?94

?95

?96

?97

?98

?99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115



116

117

118

119

120



121

122



123

124



125

126

127

128

129



130

131

132

133

134

135

136



137

138

139

140



141

142

143

144

1
<privilege?beanName="user_info"?scope="session"?operation="create">
2
????<input?type="button"?value="添加">
3
</privilege>

2

3

如此,系統(tǒng)會自動根據(jù)當(dāng)前session中的用戶來判斷是否需要顯示當(dāng)前的添加按鈕。
到此所有權(quán)限的代碼完成,在此套權(quán)限設(shè)計(jì)中,我始終抱著AOP的想法:讓他屬于一個(gè)系統(tǒng)切面,以后再開發(fā)其他系統(tǒng)時(shí),作為一個(gè)模塊就可以加載上去,與系統(tǒng)無關(guān)