Home Article Practice day08

day08

2024-07-30 09:58  views:181  source:小键人14563625    

## 1、分类导入导出优化### 1.1 后端后端数据校验#### 1、CategoryService``` boolean cateExist(Category category
);```#### 2、CategoryServiceImpl```java@Overridepublic boolean cateExist(Category category)
{ /* id已存在 或者 parent_id下 该名称的分类已存在 select count(1) from categ
ory where del_flag = 0 and id = #{category.id} or ( parent_id = #{category.
parent_id} and name = #{category.name}) LambdaQueryWrapper: 组装复杂的sql */
LambdaQueryWrapper<Category> queryWrapper = Wrappers.lambdaQuery(Category.class); /
/QueryWrapper 默认使用and的方式连接多个条件 queryWrapper.eq(Category::getId , category.getId());
//如果使用or连接的多个条件 需要作为整体 使用and连接,可以在or()方法内组装条件 //如果使用or连接的多个条件 不是整体 可以在or()方法后组装条件 q
ueryWrapper.or(q-> q.eq(Category::getParentId , category.getParentId())
.eq(Category::getName , category.getName()) ); return baseMapper.sel
ectCount(queryWrapper) > 0 ;}```#### 3、CategoryExcelDataReadListener```java@Slf4jpublic cl
ass CategoryExcelDataReadListener extends AnalysisEventListener<Category> { private Lis
t<Category> categories = new ArrayList<>(); private int limit = 10; // @Resource
CategoryService categoryService; public CategoryExcelDataReadListener(CategoryServic
e categoryService) { this.categoryService = categoryService; } @Transactional
(rollbackFor = Exception.class) @Override public void invoke(Category data, Analysis
Context context) { /* 校验读取到的数据 是不是已存在 id已存在 或者 parent_id
下 该名称的分类已存在 */ if(categoryService.cateExist(data)){ //如果读取到的一行分类
数据 已存在 继续读取下一条 //不存在 加入到批量保存的集合中 log.info("分类:{} 数据已存在" , JSON.toJSO
NString(data)); return; } categories.add(data); //判断是否触发阈值
批量保存 if(categories.size()>=limit){ categoryService.saveBatch(categories
); categories.clear(); } } @Transactional(rollbackFor = Exception.
class) @Override public void doAfterAllAnalysed(AnalysisContext context) { if
(categories.size()>0 ){ categoryService.saveBatch(categories); categ
ories.clear(); } }}```### 1.2 前端views/product/brand/index.vue```vue```### 1.3 前端
分页导航条展示异常解决ctrl+shift+R搜索: searchObj.value.total = total 替换为: searchObj.value.total = +to
tal## 2、权限管理### 2.1 常见的权限管理模型权限管理: 一般指的是后台管理系统 控制管理员权限(不同模块 不同的操作的权限 CRUD)#### 1、aclaccess
control 访问权限控制小型系统使用的权限控制模型 管理员不多```permission表: 权限表1 brand:list2 brand:delete3 brand:e
dit4 brand:saveuser表: 管理员表1 zhangsanuser_permission表: 用户权限中间表 用户和权限是多对多的关系user_id permis
sion_id1 11 4管理员 zhangsan登录时,可以查询 zhangsan的用户信息和他的权限列表,缓存到redis中{name: zhangsanid:
1permissions: ["brand:list","brand:save"]}zhangsan从前端提交 CRUD的请求时,后端可以根据登录的token 从redis'缓存
中获取它的permissions列表> 访问的接口 可以添加权限要求,通过aop(切面)接口业务执行前,可以通过切面类通知 检查接口要求的权限字符串 该用户pemissions列表
中是否包含```#### 2、rbacrole based access control 基于角色的访问控制(通过角色对权限进行了分组管理 将一组权限授权给一个角色,用户可以绑定
角色或者权限)```permission表: 权限表1 brand:list2 brand:delete3 brand:edit4 brand:saverole表: 角色表1 ad
min2 linshiadminrole_permission表: 角色权限表 角色权限 多对多role_id perssmion_id1 11 21 31 42
1user表: 管理员表1 zhangsanuser_role表: 用户角色中间表 用户和角色是多对多的关系user_id role_id1 2用户登录时,可以
查询用户的角色和权限列表{name: zhangsanid: 1permissions: ["brand:list"],roles:["linshiadmin"]}接口方法上可以要
求权限或者角色:```### 2.2 aop#### 1、若依后端权限控制流程```1、管理员登录成功后,访问页面前会先查询他的所有权限和角色如果他是admin管理员,权限为: *
:*:*> spzx-system: 权限查询 相关的表sys_usersys_user_rolesys_rolesys_role_menusys_menu> 返回的数据中就包含了
用户信息+ 管理员权限 角色列表"permissions": [ "*:*:*" ], "roles": [ "admin" ],
"user": { }2、管理员提交CRUD的请求,后端鉴权> 2.1 前端的权限控制用户只能看到自己有权操作的数据 或者 菜单前端检查权限: v-hasPe
rmi="['system:menu:add']" v-hasPermi="['system:role:add']"> 2.2 以新增角色为例1、新创建角色:角色只有查询角色列表的
权限2、新创建用户:给用户分配上面创建的权限3、前端角色页面中:删除新增角色按钮的权限要求4、后端在新增角色的接口上添加注解,要求权限检查:@RequiresPermissions
("system:role:add")注解本身没有作用,spring中通过aop给注解赋能5、鉴权的切面类:spzx-common-security: PreAuthorizeA
spect源码参考下面```--- 鉴权切面源码:```java/** * 定义AOP签名 (切入所有使用鉴权注解的方法) 切入点表达式 */public stat
ic final String POINTCUT_SIGN = " @annotation(com.spzx.common.security.annotation.Requires
Login) || " + "@annotation(com.spzx.common.security.annotation.RequiresPermissions) ||
" + "@annotation(com.spzx.common.security.annotation.RequiresRoles)";/** * 声明AOP签名
将表达式和一个方法绑定,便于以后复用切入点表达式 */@Pointcut(POINTCUT_SIGN)public void pointcut(){}/**
* 环绕切入 * * @param joinPoint 切面对象 * @return 底层方法执行后的返回值 * @throws Throwab
le 底层方法抛出的异常 pointcut() : 复用方法绑定的切入点表达式 */@Around("pointcut()")public Object aroun
d(ProceedingJoinPoint joinPoint) throws Throwable{ MethodSignature signature = (MethodS
ignature) joinPoint.getSignature(); // 注解鉴权: 传入目标方法对象 checkMethodAnnotation(signatur
e.getMethod()); try { // 执行原有逻辑 Object obj = joinPoint.proceed();
return obj; } catch (Throwable e) { throw e; }}/** * 对一个Method对象
进行注解检查 */public void checkMethodAnnotation(Method method){ // 校验 @RequiresLogin 注解
RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class); if (require
sLogin != null) { //对使用了RequiresLogin注解的接口方法 进行登录鉴权 //如果请求头没有携带 token,或者携
带的token解析失败,或者token解析不到user对象 直接抛出异常 AuthUtil.checkLogin();//已登录 校验通过 继续向后执行 }
// 校验 @RequiresRoles 注解 RequiresRoles requiresRoles = method.getAnnotation(RequiresRo
les.class); if (requiresRoles != null) { AuthUtil.checkRole(requiresRoles);
} // 校验 @RequiresPermissions 注解 RequiresPermissions requiresPermissions = method.g
etAnnotation(RequiresPermissions.class); if (requiresPermissions != null) { A
uthUtil.checkPermi(requiresPermissions); }}```AuthUtil```java//perssmion鉴权public static
void checkPermi(RequiresPermissions requiresPermissions){ authLogic.checkPermi(require
sPermissions);}public void checkPermi(RequiresPermissions requiresPermissions){ Securit
yContextHolder.setPermission(StringUtils.join(requiresPermissions.value(), ",")); if (r
equiresPermissions.logical() == Logical.AND) { checkPermiAnd(requiresPermissions
.value()); } else { checkPermiOr(requiresPermissions.value()); }}public
void checkPermiAnd(String... permissions){ Set<String> permissionList = getPermiList()
;//获取登录用户的权限列表 for (String permission : permissions)//遍历接口上注解要求的权限列表 { if (!h
asPermi(permissionList, permission))//只要有任意一个权限 用户没有 抛出异常 //超级管理员 权限字符串为 *:*:*
{ throw new NotPermissionException(permission); } }}public vo
id checkPermiOr(String... permissions){ Set<String> permissionList = getPermiList();
for (String permission : permissions) { if (hasPermi(permissionList, permission
)) { return; } } if (permissions.length > 0) { th
row new NotPermissionException(permissions); }}//角色鉴权的业务:public static void checkRole(R
equiresRoles requiresRoles){ authLogic.checkRole(requiresRoles);//requiresRoles表示接口要求的角
色注解对象}public void checkRole(RequiresRoles requiresRoles){ if (requiresRoles.logical() =
= Logical.AND) //获取角色注解对象的 logical属性值,and或者or { //注解中要求的多个角色 必须同时拥有 check
RoleAnd(requiresRoles.value()); } else { //注解中的多个角色 有一个即可 checkRole
Or(requiresRoles.value()); }}public void checkRoleAnd(String... roles){ Set<String>
roleList = getRoleList();//获取登录用户的角色列表 for (String role : roles) //遍历接口要求的角色列表 {
if (!hasRole(roleList, role))//检查用户的角色列表中有任意一个不包含接口要求的角色 抛出异常 //如果用户角色是admi
n 所有接口都可以访问 { throw new NotRoleException(role); } }}public vo
id checkRoleOr(String... roles){ Set<String> roleList = getRoleList(); for (String r
ole : roles) { if (hasRole(roleList, role))//用户有任意一个接口要求的角色 直接解析校验 继续执行 {
return; } } if (roles.length > 0) { throw new NotRoleEx
ception(roles); }}``````若依权限控制:1、前端访问页面前 会加载用户信息和他的角色以及权限列表2、前端渲染页面时: 可以通过 v-hasPermi
v-hasRole... 校验加载的角色和权限列表 如果包含则展示标签 否则不展示3、后端接收到用户的CRUD请求时,如果接口方法上加了 RequiresRoles Req
uiresPermissions 注解 会被PreAuthorizeAspect的环绕通知 进行动态代理增强> 对用户的登录状态 角色 权限 按照注解的要求进行检查本质 就是字符串
比较若依菜单管理:目录菜单: 项目:模块:list按钮: 项目:模块:delete 项目:模块:edit 项目:模块:save```### 2.3 自定义aop打印接口访
问日志#### 1、自定义注解```SpzxPrintLogmodule : 模块名称isPrintRequestParam: 是否打印请求参数isPrintResult : 是否
打印响应结果```#### 2、切面类对自定义注解进行增强(通过环绕通知处理)#### 3、使用在需要打印日志的接口上使用自定义注解```接口执行的时长,所属模块名称,打印请求参数
,返回值```### 2.4 使用若依的权限控制#### 1、超级管理员给普通角色分配权限#### 2、接口上使用权限注解以BrandController为例:```java@Op
eration(summary = "批量删除品牌")@RequiresPermissions(value = {"product:brand:remove"})@Log(titl
e = "删除品牌" ,businessType = BusinessType.DELETE )@DeleteMapping("{ids}")public AjaxResult l
ist(@PathVariable("ids") List<Long> ids) {```#### 3、前端权限校验以brand/index.vue为例```vue<el-butt
on size="small" type="danger" @click="handleDelete(scope.row
)" v-hasPermi="['product:brand:remove']" > 删除</el-button>```### 2.5
若依操作日志记录### 2.6 任务:断点查看若依记录操作日志的流程## 3、spzx-gen代码生成器的使用### 3.1 修改nacos配置naocs配置中心 spzx-g
en-dev.yml 数据库连接修改为 spzx-user账号密码修改为 spzx-user数据库的账号密码逆向工程包名修改为 com.spzx.user```yaml```###
3.2 spzx-user库创建逆向工程表```将gen_table和gen_table_column这两张表加入spzx-user库,存在就忽略```### 3.3 逆向工程后
天管理系统 系统工具--->代码生成 可以选择导入表之后 点击生成## 4、spzx-user服务搭建### 4.1 创建项目**在spzx-modules下创建spzx-us
er****pom文件引入依赖:拷贝spzx-product的****bootstrap.yml**```yml```### 4.2 nacos配置文件克隆 spzx-produc
t-dev 修改为 spzx-user-dev修改spzx-user-dev中连接的数据库名称 为spzx-user### 4.3 启动类```java@SpringBootAp
plication@EnableCustomConfig@EnableRyFeignClientspublic class SpzxUserApplication { pub
lic static void main(String[] args) { SpringApplication.run(SpzxUserApplication.cla
ss, args); }}```### 4.4 将逆向工程的类和mapper导入到项目中### 4.5 修改UserInfo添加扩展字段: 接收前端查询请求以及 用户地址列表
```java@Schema(description = "注册开始时间")@TableField(exist = false)@ExcelIgnoreprivate String
begin;@Schema(description = "注册截至时间")@ExcelIgnore@TableField(exist = false)private String
end;@ExcelIgnore@TableField(exist = false)private List<UserAddress> userAddressList;```##
# 4.6 UserInfoController```java@Operation(summary = "获取会员详细信息")@RequiresPermissions("user:
userInfo:query")@GetMapping(value = "/{id}")public AjaxResult getInfo(@PathVariable("id")
Long id){ UserInfo userInfo = userInfoService.getUserInfoAndAddressedById(id); retur
n success(userInfo);}```### 4.7 UserInfoService``` UserInfo getUserInfoAndAddressedById
(Long id);```### 4.8 UserInfoServiceImpl```java@Overridepublic UserInfo getUserInfoAndAddr
essedById(Long id) { UserInfo userInfo = this.getById(id); List<UserAddress> userAdd
resses = userAddressMapper.selectList(Wrappers.lambdaQuery(UserAddress.class)
.eq(UserAddress::getUserId, id));
userInfo.setUserAddressList(userAddresses); return userInfo;}```### 4.9 UserInfoMapper
.xml按照前端传入的条件查询```xml```### 4.10 前端#### 1、创建菜单路由#### 2、导入api#### 3、导入页面#### 4、修改页面



Disclaimer: The above articles are added by users themselves and are only for typing and communication purposes. They do not represent the views of this website, and this website does not assume any legal responsibility. This statement is hereby made! If there is any infringement of your rights, please contact us promptly to delete it.

字符:    改为:
去打字就可以设置个性皮肤啦!(O ^ ~ ^ O)