JeeSite学习笔记
开发环境
- java 1.8.0
- Maven 3.6.2 --D:\apache-maven-3.6.2
- Intellij IDEA
- Mysql 8.0
- Git – ToroiseGit
本地运行测试
- 执行脚本/web/bin/run-tomcat.bat
- 访问 http://127.0.0.1:8980/js/ 账号 system 密码 admin
开发环境部署
导入到IDEA
- 获取源码
- 拷贝web文件夹,到工作目录,重命名为:
jeesite-test
- 打开pom.xml文件,找到jeesite-web的artifactId元素,修改为
jeesite-test
- Eclipse:菜单 File -> Import,然后选择 Maven -> Existing Maven Projects,点击 Next> 按钮,选择第2步的
jeesite-test
文件夹,然后点击 Finish 按钮,即可成功导入。 - IDEA:点击 Open 或 Import Project,选择
pom.xml
文件(若包含所有源码包,你需要选择jeesite/root/pom.xml
文件),点击 Next 按钮,选择Import Maven projects automatically
复选框,然后一直点击 Next 按钮,直到点击 Finish 按钮,即可成功导入。
问题
- 错误1(IDEA)
Could not transfer artifact xxx from/to maven-default-http-blocker (http://0.0.0.0/)
- 解决方法
手动删除 settings.xml 里的 id 为 maven-default-http-blocker 镜像,因为 maven 3.8 版本后增加了这个镜像,导致的请求错误;IDEA 下请打开 IDEA 所在安装目录,找到 \plugins\maven\lib\maven3\conf\settings.xml 文件,并删除 maven-default-http-blocker 镜像配置。
- 未解决为题:(pom.xml)
- Cannot resolve directory ‘parent’
- Plugin ‘org.apache.maven.plugins:maven-war-plugin:’ not found
- Plugin ‘org.apache.maven.plugins:maven-eclipse-plugin:’ not found
初始化数据库
- 配置JDBC链接 /src/main/resources/config/application.yml:
## 产品或项目名称、软件开发公司名称
productName: 修改为你的产品名称
companyName: 修改为你的公司名全称
## 产品版本、版权年份
productVersion: V4.3
copyrightYear: 2022
## 数据库连接
jdbc:
# MySql 数据库配置(提示:v4.2 及之后使用 MySql 8.x 驱动类的配置方法)
type: mysql
driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jeesite?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=UTC
username: root
password: 123456
testSql: SELECT 1
## MySql 数据库配置(提示:v4.1 及之前使用 MySql 5.x 驱动类的配置方法)
type: mysql
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jeesite?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
username: jeesite
password: jeesite
testSql: SELECT 1
- 初始化数据库/web/bin/init-data.bat
启动服务
- Eclipse:找到
Application.java
(专业版:ProApplication.java
)启动文件并打开,然后在空白处右键,点击 Debug As -> Java Application 即可启动服务。 - IDEA:右上选择
Application
(专业版:ProApplication
)运行配置,点击 Debug 图标,启动服务。如果启动的时候提示NoClassDefFoundError: javax/servlet/ServletOutputStream
错误,请修改 web 项目下的 pom.xml,注释掉spring-boot-starter-tomcat
的<scope>provided</scope>
即可。
运行测试
- 访问http://127.0.0.1:8980/js
- 账号:system 密码:admin
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3qHvWWlo-1678673430427)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20221220140355858.png)]
清理Demo数据
DELETE FROM js_sys_post;
DELETE FROM js_sys_office;
DELETE FROM js_sys_company;
DELETE FROM js_sys_employee;
DELETE FROM js_sys_employee_post;
DELETE FROM js_sys_role WHERE role_code NOT IN ('corpAdmin','default');
DELETE FROM js_sys_role_data_scope;
DELETE FROM js_sys_user WHERE user_code NOT IN ('system','admin');
DELETE FROM js_sys_user_data_scope;
DELETE FROM js_sys_user_role;
DELETE FROM js_sys_log;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EoMhrgF-1678673430433)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20221220140739258.png)]
新建模块工程
进入菜单:系统管理 -> 系统设置 -> 模块管理,新建一个模块:
- 模块名称: 测试模块
- 模块编码:test
- 生成基础路径:D:\JeeSite_workspace
- 代码生成模板:生成模块代码
点击“保存并生成代码”
打开/root/pom.xml文件,拷贝…/modules/core到新的一行,修改为模块名如:…/modules/test
在需要用到的项目引入新的模块,如在web项目下使用,则打开/web/pom.xml文件加入:
<dependency>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-module-test</artifactId>
<version>${project.parent.version}</version>
</dependency>
IDEA 会自动检测 root 模块的依赖,并自动导入
创建模块结束
问题
- 创建模块之后的用法----->
建表以及ErMaster的使用
ErMaster安装方式
- 下载Eclipse的ErMaster插件安装包:https://gitee.com/thinkgem/ermasterr
- 找到plugins中的jar包:D:\JeeSite\ermasterr-master.zip\ermasterr-master\dropins\ermasterr\eclipse\plugins
- 复制到Eclipse的plugins中,启动Eclipse
ErMaster使用以及建表
- 打开表的模板
- 打开table,双击表视图
- 添加字段
- 内置字段组
- 新增公共字段
- 导出表
菜单权限、功能权限、资源权限、按钮权限、Shiro
用户身份认证
验证用户身份的合法性:
最常用的用户身份验证的方法:
- 用户名、密码方式:通过登录界面进入系统
- 用户名、安全密钥方式:通过SSO接口或OAuth2接口进入系统
- 基于硬件或证书验证方法:通过特定的硬件或证书进入系统
也就是说,系统验证用户身份合法,用户方可访问系统的资源。
- 主体对象(Subject):理解为用户,可能是程序,都要去访问系统的资源,系统需要对subject进行身份认证,获取方法:UserUtils.getSubject()
- 身份信息(Principal):通常是唯一的,一个主体还有多个身份信息,但是都有一个主身份信息(Primary principal),获取方法:UserUtils.getLoginInfo()
用户权限授权
是对用户身份认证的细化。可简单理解为访问控制,在用户身份认证通过后,系统对用户访问菜单或按钮进行控制。也就是说,该用户有身份进入系统了,但他不一定能访问系统里的所有菜单或按钮,而他只能访问管理员给他分配的权限菜单或按钮。
主要包括:
- Permission(权限标识、权限字符串):针对系统访问资源的权限标识,如:用户添加、用户修改、用户删除,判断方法:UserUtils.getSubject().isPermitted(permissions);
- Role (角色):可以理解为权限组,也就是说角色下可以访问和点击哪些菜单、访问哪些权限标识。
权限标识或权限字符串校验规则:
- 权限字符串:指定权限串必须和菜单中的权限标识匹配才可访问
- 权限字符串命名规范为:
模块:功能:操作
,例如:sys:user:edit
- 使用冒号分隔,对授权资源进行分类,如
sys:user:edit
代表系统模块:用户功能:编辑操作
- 设定的功能指定的
权限字符串
与当前用户的权限字符串
进行匹配,若匹配成功说明当前用户有该功能权限 - 还可以使用简单的通配符,如
sys:user:*
,建议省略为sys:user
(分离前端不能使用星号写法) - 举例1
sys:user
将于sys:user
或sys:user:
开头的所有权限字符串匹配成功 - 举例2
sys
将于sys
或sys:
开头的所有权限字符串匹配成功
权限管理模型
JeeSite 中的权限管理关键数据模型如下:
- 用户:登录账号、密码、用户类型
- 角色:角色名称、归属用户类型
- 菜单:菜单名称、菜单URL、权限标识
- 用户角色关系:用户编码、角色编码
- 角色菜单关系:角色编码、菜单编码
关系图如下:
【用户】 <---多对多---> 【角色】 <---多对多---> 【菜单/权限】
权限配置步骤
- 进入菜单管理:新增菜单和权限。其中权限类型的菜单,也可理解为系统资源,不会显示到用户菜单树中。
- 菜单中的 “权限标识” 即 Permission 是控制权限的关键字段,系统根据该权限标识 与 Controller 内指定的 @RequiresPermissions 注解进行对应,匹配成功后才可以访问该 URL 地址,此例是注解式验证。另外还有编程式、视图页面、URI控制方式,详见下文。
- 菜单配置完成后,进入角色管理:新增并给角色的功能权限,勾选对应的菜单和权限,建立角色菜单的关系。
- 角色配置完成后,进入机构管理及用户管理,创建机构,创建用户,选择相应角色,建立用户和角色关系。
- 这样整个权限体系建立完成,用户登录系统后,就可以通过用户关联的角色,获取菜单/权限了。
- 若提示“403 - 您的操作权限不足”,说明对应的 URL 当前用户没有权限访问,检查 Controller 的映射方法上的 @RequiresPermissions 注解,是否在 “菜单管理” 里的 “权限字符串” 中配置了,并且当前用户对应的角色是否拥有该权限菜单。
管理员类型
- 超级管理员:主要为开发者使用的最高级别管理员,主要用于开发和调试,有些修改会直接影响系统的正常运行。
- 系统管理员:主要为客户方使用的管理员,用于一些基础数据配置,如机构、用户、权限、用户字典等,默认账号为admin。
- 二级管理员,是由系统管理员指定的,可以分担系统管理员的工作,可以管理用户、分配菜单权限和操作权限一种特殊角色,但它仅具备系统管理员指定范围的管理数据。
菜单权重
菜单权重是指什么样的用户或管理员可以操作或访问什么级别的菜单,对菜单的权重级别进行划分,比如:比较重要敏感的菜单,只有管理员才可以拥有。如下:
- 超级管理员可以访问二级管理员、系统管理员、超级管理员权重的菜单,但不允许访问默认权限(业务菜单);
- 系统管理员可以访问超级管理员指定给他的系统管理员及以下权限的部分菜单;
- 二级管理员可以访问超级或系统管理员指定给他的二级管理员及以下的部分菜单;
- 普通用户只能访问管理员指定给他的默认权重的菜单。
菜单权重的设置,会影响角色授权菜单的时候,列出的菜单和权限列表:
- 如果当前用户管理身份为二级管理员,则列出的是二级管理员菜单权重以下的菜单;
- 如果当前用户管理员身份是系统管理,则列出的是系统管理员菜单权重以下的菜单;
- 如果当前用户管理员身份是超级管理员,则列出的是超级管理员菜单权重下的菜单。
此举是为了更好的提高授权安全,不能越级授权,权限互相牵制等。
四种授权方式
- 编程式:通过 if/else 代码块来完成。
- 注解式:通过在执行的方法上放置相应的注解来完成,没有权限则抛出相应异常。
- 视图页面: 在视图页面(Beetl/JSP)通过相应的标签完成。
- 基于URI拦截:根据URI匹配,决定访问权限。
编程式
场景:编辑和审核共用一个资源,可以在资源内判断是否有审核权限,然后再去执行对应操作
Subject subject = UserUtils.getSubject();
subject.isAuthenticated(); // 是否身份验证授权通过
subject.isPermitted(permission); // 验证权限字符串
subject.isPermittedAll(permissions); // 验证权限字符串全部通过
subject.hasRole(roleIdentifier); // 验证是否有角色权限
例如:
if (subject.isPermitted("sys:user:edit")){
System.out.pirntln("当前用户有编辑用户权限");
}
注解式
场景:对 URL 资源、按钮 等操作进行权限过滤,如果用户跳过了界面验证,直接去访问 URL 地址也需要经过授权验证的。
在Controller的方法上指定如下注解:
- @RequiresPermissions (value={“sys:user:view”, “sys:user:edit”}, logical= Logical.OR):表示当前 Subject 需要权限 user:view 或 user:edit。
- @RequiresRoles(value={“admin”, “user”}, logical=Logical.AND):表示当前 Subject 需要角色 admin 和 user
- @RequiresAuthentication:表示当前Subject已经通过login进行了身份验证;
- @RequiresUser:表示当前 Subject 已经身份验证或者通过记住我登录的。
- @RequiresGuest:表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。
例如:
@RequiresPermissions(value="sys:user:edit")
@PostMapping(value = "save")
@ResponseBody
public String save(@Validated User user, HttpServletRequest request) {
}
视图页
场景:在视图上通过权限字符串,控制某个按钮或某个信息是否显示,提高用户体验。
判断是否有该权限:
- 单个权限验证:${hasPermi(‘sys:user:edit’)}
- 多个AND关系:${hasPermi(‘sys:user:view,sys:user:edit’, ‘and’)}
- 多个OR关系:${hasPermi(‘sys:user:view,sys:user:edit’, ‘or’)}
例如:
<% if(hasPermi('sys:user:edit')){ %>
<a href="${ctx}/sys/user/form" class="btn btn-default btnTool"
title="新增用户"><i class="fa fa-plus"></i> 新增</a>
<% } %>
判断是否有某角色:
- 单个权限验证:${hasRole(‘ceo’)}
- 多个AND关系:${hasRole(‘ceo,dept’, ‘and’)}
- 多个OR关系:${hasRole(‘ceo,dept’, ‘or’)}
例如:
<% if(hasRole('ceo')){ %>
<span>ceo</span>
<% } %>
基于RUI拦截
场景:当不方便利用编程式、注解式等方式过滤权限时,可以使用 URI 控制权限,或全局控制某个 URI 地址的权限
application.yml(4.0.x:jeesite.yml):
shiro:
# URI 权限过滤器定义
filterChainDefinitions: |
/ReportServer/** = user
${adminPath}/** = user
格式:
URI地址及通配符 = 过滤器名称(支持多个,用英文逗号分隔并加双引号)
以上权限过滤器定义配置,是依照由上到下的第一次匹配优先原则,优先匹配成功的URI优先受用,支持通配符。
URI通配符:
? :匹配一个字符。
* :匹配零个或多个字符串。
** :匹配路径中的零个或多个路径。
认证过滤器名称:
- anon: 例如
/a/file/**=anon
没有参数,表示不需要登录,就可以访问资源 - user: 例如
/a/sys/user/**=user
没有参数,表示必须用户登录后才能访问资源,当登入操作时不做检查 - authc: 例如
/a/login=authc
没有参数,表示需要登录认证才能访问资源,一般用于登录接口
授权过滤器名称:
- perms:例如
/a/sys/user/**=perms[user:add:*]
,参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/a/sys/user/**=perms["user:add:*,user:modify:*"]
,当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。 - roles:例如
/a/sys/user/**=roles[admin]
,参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如/a/sys/user/**=roles["admin,guest"]
,每个参数通过才算通过,相当于hasAllRoles()方法。
**注意事项:**增加新的过滤器的时候,不要删掉默认的过滤器,顺序从上到下依次匹配,先符合条件的优先使用。如果默认的过滤器被删除,会话超时后,将不会跳转到登录页,则直接返回403页面。
我的测试
增加一个用户管理模块
-
启动服务
-
登录–http://127.0.0.1:8980/js
-
账号:system 密码:admin
-
用户管理
-
建表
-
在eclipse中找到core.erm(jeesite官方提供的表模板)
-
找到用户表的模板
-
导出表
-
在数据库中导入新的表
-
-
使用研发工具中–代码生成工具
-
找到刚刚导入的表
-
新增的信息–基本信息–字段信息–生成信息
-
点击下一步–保存并生成代码
-
-
-
查看生成的代码
-
将新模块添加到系统中
-
-
在后台的管理菜单面板中找到系统设置->菜单管理->组织管理->用户管理
-
进入用户管理页面
-
在用户管理中新增下级菜单
新增的下级菜单 -
为系统管理员添加权限
-
重启服务,即可。
-