[TOC]
后台管理系统演示地址:http://ry-spzx-admin.atguigu.cn/
移动端演示地址:http://ry-spzx.atguigu.cn/
尚品甄选
是基于若依微服务版本
开发的一个电商系统,项目包含平台管理端与手机H5端。有一套完善的电商业务流程:包含商品管理、商品详情、单点登录、购物车、订单、支付、库存管理等,其中覆盖了分布式文件系统、缓存、消息队列等多种业务场景和技术实现。
电商网站有很多典型的特征:
B2B(Business to Business)
指进行交易的供需双方都是商家(或企业、公司)。
案例:阿里巴巴1688
C2C(Consumer to Customer)
或Customer to Customer,意思就是消费者个人间的电子商务行为。
案例:淘宝、闲鱼
B2C(Business-to-Customer)
简称“商对客”,商家直接面向消费者销售产品和服务的模式。
案例:京东自营
B2B2C(Business to Business to Consumer)
第一个B指服务供应商,为商家提供销售平台,第二个B指商家,C表示消费者。
案例:天猫商城
C2B(Consumer to Business)
消费者到商家,先有消费者需求产生,后有商家提供商品或服务。
案例:猪八戒
O2O(Online To Offline)
线上到线下,指线上下单线下服务。
案例:美团、饿了么
前端技术栈
在资料中找到xxx.tar
,上传到服务器中,并还原镜像
docker load -i minio.tar
docker load -i mysql.tar
docker load -i nacos.tar
docker load -i rabbitmq.tar
docker load -i redis.tar
docker load -i sentinel.tar
在资料中找到docker-compose.yml
,上传到服务器中,并执行命令
# 启动容器(如果不存在容器就创建、存在则修改)
docker compose -f docker-compose.yml up -d
# 其他命令
# 停止所有容器
docker compose -f docker-compose.yml stop
# 启动所有容器
docker compose -f docker-compose.yml start
# 重启所有容器
docker compose -f docker-compose.yml restart
# 删除所有容器
docker compose -f docker-compose.yml down
MySQL如果无法远程连接,如下,则修改密码校验方式
#进入容器
docker exec -it spzx-mysql /bin/bash
#进入mysql命令行
mysql -uroot -p
#修改默认密码校验方式
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';
http://192.168.200.10:8848/nacos
账号密码:nacos/nacoshttp://192.168.200.10:15672
账号密码:guest/guesthttp://192.168.200.10:9001
账号密码:admin/admin123456http://192.168.200.10:8858
账号密码:sentinel/sentinel微服务版本:https://doc.ruoyi.vip/ruoyi-cloud/
源码下载:https://ruoyi.vip/,下载`RuoYi-Cloud 微服务版`
环境部署:环境部署 | RuoYi
RuoYi-Cloud 是一个 Java EE 分布式微服务架构平台,基于经典技术组合(Spring Boot、Spring Cloud & Alibaba、Vue、Element),内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、代码生成等。在线定时任务配置;支持集群,支持多数据源。
当前的RuoYi-Cloud版本是3.6.3,其中jdk版本为1.8,spring-boot版本为2.7.18,不是我们预期的版本。
因此我们在此基础上做了升级,升级后的版本如下:
第一步:找到项目初始源码spzx-parent.rar
,解压并复制到工作空间
第二步:修改maven配置为自己的Maven相关路径
第三步:导入项目源码到idea
若依原生自带的项目模块如下:
com.ruoyi
├── ruoyi-ui // 前端框架 [80]
├── ruoyi-gateway // 网关模块 [8080]
├── ruoyi-auth // 认证中心 [9200]
├── ruoyi-api // 接口模块
│ └── ruoyi-api-system // 系统接口
├── ruoyi-common // 通用模块
│ └── ruoyi-common-core // 核心模块
│ └── ruoyi-common-datascope // 权限范围
│ └── ruoyi-common-datasource // 多数据源
│ └── ruoyi-common-log // 日志记录
│ └── ruoyi-common-redis // 缓存服务
│ └── ruoyi-common-seata // 分布式事务
│ └── ruoyi-common-security // 安全模块
├── ruoyi-modules // 业务模块
│ └── ruoyi-system // 系统模块 [9201]
│ └── ruoyi-gen // 代码生成 [9202]
│ └── ruoyi-job // 定时任务 [9203]
│ └── ruoyi-file // 文件服务 [9300]
├── ruoyi-visual // 图形化管理模块
│ └── ruoyi-visual-monitor // 监控中心 [9100]
├──pom.xml // 公共依赖
我们将其包名和模块名进行了修改如下:
com.spzx
├── spzx-gateway // 网关模块 [8080]
├── spzx-auth // 认证中心 [9200]
├── spzx-api // 接口模块
│ └── spzx-api-system // 系统接口
├── spzx-common // 通用模块
│ └── spzx-common-core // 核心模块
│ └── spzx-common-datascope // 权限范围
│ └── spzx-common-datasource // 多数据源
│ └── spzx-common-log // 日志记录
│ └── spzx-common-redis // 缓存服务
│ └── spzx-common-seata // 分布式事务
│ └── spzx-common-security // 安全模块
├── spzx-modules // 业务模块
│ └── spzx-system // 系统模块 [9201]
│ └── spzx-gen // 代码生成 [9202]
│ └── spzx-file // 文件服务 [9300]
├── spzx-visual // 图形化管理模块
│ └── spzx-monitor // 监控中心 [9100]
├──pom.xml // 公共依赖
执行数据库脚本:在资料中找到 spzx-xxx.sql
第一步:导入配置
nacos配置
第二步:修改nacos配置。涉及数据源的地方都要修改,mysql、redis、minio等等,地址需要修改为自己虚拟机的地址
第三步:修改spzx-gateway、spzx-auth、spzx-system、spzx-file、spzx-gen、spzx-monitor块的本地配置文件。涉及nacos配置中心、注册中心地址、sentinel地址等
第四步:启动如
下模块:spzx-gateway、spzx-auth、spzx-system、spzx-file、spzx-gen、spzx-monitor
替换前端项目:在资料中找到 spzx-ui.zip
,解压文件
# node版本 v18
node -v
#进入前端目录
cd spzx-ui
# 安装依赖
npm install
# 本地开发 启动项目
npm run dev
# 构建测试环境 npm run build:stage
# 构建生产环境 npm run build:prod
默认登录用户名:admin/admin123
第一次基于若依创建模块可以参考spzx-system
在spzx-modules模块下新建子模块spzx-product
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.spzx</groupId>
<artifactId>spzx-modules</artifactId>
<version>3.6.3</version>
</parent>
<artifactId>spzx-product</artifactId>
<description>
spzx-product系统模块
</description>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- RuoYi Common DataScope -->
<dependency>
<groupId>com.spzx</groupId>
<artifactId>spzx-common-datascope</artifactId>
</dependency>
<!-- RuoYi Common Log -->
<dependency>
<groupId>com.spzx</groupId>
<artifactId>spzx-common-log</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
在resources目录下新建banner.txt
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
_ _
(_) | |
_ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___
| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \
| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | |
|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_|
__/ | __/ |
|___/ |___/
在resources目录下新建bootstrap.yml
# Tomcat
server:
port: 9205
# Spring
spring:
application:
# 应用名称
name: spzx-product
profiles:
# 环境配置
active: dev
main:
allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.200.10:8848
config:
# 配置中心地址
server-addr: 192.168.200.10:8848
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
在nacos上添加商品服务配置文件
mybatis-plus:
mapper-locations: classpath*:mapper/**/*Mapper.xml
type-aliases-package: com.spzx.**.domain
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 查看日志
global-config:
db-config:
logic-delete-field: del_flag # 全局逻辑删除的实体字段名
logic-delete-value: 2 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
# spring配置
spring:
data:
redis:
host: 192.168.200.10
port: 6379
password:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.10:3306/spzx-product?characterEncoding=utf-8&useSSL=false
username: root
password: root
hikari:
connection-test-query: SELECT 1
connection-timeout: 60000
idle-timeout: 500000
max-lifetime: 540000
maximum-pool-size: 10
minimum-idle: 5
pool-name: GuliHikariPool
在resources目录下新建logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/spzx-product" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%yellow(%d{HH:mm:ss.SSS}) [%thread] %green(%-5level) %cyan(%logger{20}) - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.spzx" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>
添加启动类
package com.spzx.product;
/**
* 商品模块
*
* @author spzx
*/
@EnableCustomConfig
@EnableRyFeignClients
@SpringBootApplication
public class SpzxProductApplication
{
public static void main(String[] args)
{
SpringApplication.run(SpzxProductApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 系统模块启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}
参考文档:代码生成器 | MyBatis-Plus
在spzx-parent的dependencyManagement中添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.32</version>
</dependency>
在spzx-common-core中添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
在test目录中创建代码生成器
package com.spzx.product;
public class GenMP {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://192.168.200.10:3306/spzx-product?characterEncoding=utf-8&useSSL=false", "root", "root")
.globalConfig(builder -> builder
.author("atguigu")
.outputDir("D:/spzx/product")
.dateType(DateType.ONLY_DATE)
.disableOpenDir()
)
.packageConfig(builder -> builder
.parent("com.spzx.product")
.entity("domain")
.mapper("mapper")
.xml("mapper.product")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
)
.strategyConfig(builder -> builder
.addInclude(
"brand",
"category",
"category_brand",
"product",
"product_details",
"product_sku",
"product_spec",
"product_unit",
"sku_stock") // 设置需要生成的表名
.entityBuilder()
.enableLombok()
.superClass(BaseEntity.class)
.addSuperEntityColumns(
"id",
"create_by",
"create_time",
"update_by",
"update_time",
"remark",
"del_flag")
//.addIgnoreColumns
.enableFileOverride()
.serviceBuilder()
//.formatServiceFileName("I%sService")
.enableFileOverride()
.controllerBuilder()
.superClass(BaseController.class)
.enableRestStyle()
.enableFileOverride()
)
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
}
将java文件复制在src/main/java
将XxxMapper.xml文件复制到src/main/resources/mapper/product目录下
创建远程仓库并获取仓库地址
1、访问minio管理页面:http://192.168.200.10:9001 账号密码:admin/admin123456
2、创建bucket:spzx
3、设置访问权限
{
"Statement" : [ {
"Action" : "s3:GetObject",
"Effect" : "Allow",
"Principal" : "*",
"Resource" : "arn:aws:s3:::spzx/*"
} ],
"Version" : "2012-10-17"
}
1、启动spzx-file微服务
2、访问swagger测试文件上传:http://localhost:9300/doc.html
同步时间:
第一步:安装ntp服务
yum -y install ntp
第二步:开启开机启动服务
systemctl enable ntpd
第三步:启动服务 Tips:联网正常前提下如果定时同步失败,先停止服务,再启动
systemctl stop ntpd
systemctl start ntpd
第四步:更改时区
timedatectl set-timezone Asia/Shanghai
第五步:启用ntp同步
timedatectl set-ntp yes
第六步:同步时间
ntpq -p
品牌管理就是对商品的所涉及到的品牌数据进行维护。
package com.spzx.product.domain;
@Schema(description = "品牌")
@Getter
@Setter
@TableName("brand")
public class Brand extends BaseEntity
{
private static final long serialVersionUID = 1L;
@Schema(description = "品牌名称")
private String name;
@Schema(description = "品牌图标")
private String logo;
}
查询品牌分页列表接口
package com.spzx.product.controller;
@Tag(name = "品牌管理")
@RestController
@RequestMapping("/brand")
public class BrandController extends BaseController{
@Autowired
private IBrandService brandService;
@Operation(summary = "查询品牌列表")
@GetMapping("/list")
public TableDataInfo list(@Parameter(description = "品牌名称") String name){
//分页参数封装到了BaseController类
startPage();
List<Brand> list = brandService.selectBrandList(name);
return getDataTable(list);
}
}
List<Brand> selectBrandList(String name);
@Override
public List<Brand> selectBrandList(String name) {
LambdaQueryWrapper<Brand> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(name), Brand::getName, name);
return baseMapper.selectList(queryWrapper);
}
启动项目
访问在线swg:http://localhost:9205/doc.html
注意分页参数使用:?pageNum=1&pageSize=10
@Operation(summary = "获取品牌详细信息")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id){
return success(brandService.getById(id));
}
@Operation(summary = "新增品牌")
@PostMapping
public AjaxResult add(@Parameter(description = "品牌") @RequestBody Brand brand) {
//设置当前用户
brand.setCreateBy(SecurityUtils.getUsername());
return toAjax(brandService.save(brand));
}
测试数据
{
"name": "大米",
"logo": "http://139.198.127.41:9000/spzx/2024/02/03/xm_20240203154528A007.png"
}
@Operation(summary = "修改品牌")
@PutMapping
public AjaxResult edit(@Parameter(description = "品牌") @RequestBody Brand brand) {
//设置当前用户
brand.setUpdateBy(SecurityUtils.getUsername());
return toAjax(brandService.updateById(brand));
}
测试数据
{
"id": 7,
"name": "中米"
}
@Operation(summary = "删除品牌")
@DeleteMapping("/{ids}")
public AjaxResult remove(
@Parameter(description = "品牌id列表", example = "[1,2]")
@PathVariable List<Long> ids) {
return toAjax(brandService.removeBatchByIds(ids));
}
测试数据:多个id用逗号分隔
在nacos配置中心:spzx-gateway-dev.yml文件添加商品服务的路由配置信息
# 商品服务
- id: spzx-product
uri: lb://spzx-product
predicates:
- Path=/product/**
filters:
- StripPrefix=1
系统管理 -> 菜单管理 -> 新增 -> 主类目
商品管理
品牌管理
权限控制
主要目的是保护系统的安全性和完整性,防止未经授权的用户获取敏感信息、执行非法操作或对系统进行恶意操作 。
常见的权限控制框架有 SpringSecurity 和 Apache Shiro。
若依的权限管理是通过 RBAC
(Role-based Access Control 基于角色的访问控制)模型自己设计的。
RBAC模型将权限控制分为角色管理和权限管理两个部分。通过为每个角色分配相应的权限,可以实现对系统的全面管理和控制。
在数据库表结构方面,若依采用了RBAC模型的设计。其中,主要包括以下表:
sys_menu
:系统菜单(权限)sys_role
:系统角色sys_user
:系统用户sys_role_menu
:角色和菜单之间的关联关系sys_user_role
:用户和角色之间的关联关系sys_menu表的数据分为三个级别:目录、菜单、按钮。现在我们在品牌管理
菜单下添加按钮:
在系统管理=>用户管理
创建用户:
在系统管理=>角色管理
创建角色,并为角色分配菜单权限和用户:
spzx-ui/src/views/product/brand/index.vue
<el-button type="primary" plain icon="Plus"
@click="handleAdd"
v-hasPermi="['product:brand:add']">
新增
</el-button>
前端会根据权限标志显示或者隐藏按钮,但是如果用户不点击按钮,直接通过http请求工具请求后端咋办?所以接口权限也是要有的。
若依系统实现了这部分功能,实现模块:spzx-common-security
。
底层原理:拦截器HeaderInterceptor
负责解析用户token信息,并将解析出的用户信息存入ThreadLocal
中,然后PreAuthorizeAspect
负责解析权限注解,判断当前用户是否拥有注解权限。
@RequiresLogin
注解用于配置接口要求用户必须登录才可访问
示例1: 以下代码表示必须登录才可访问
@RequiresLogin
public AjaxResult allCheckCart(){
return success();
}
@RequiresPermissions
注解用于配置接口要求用户拥有某(些)权限才可访问,它拥有两个参数
参数 | 类型 | 描述 |
---|---|---|
value | String[] | 权限列表 |
logical | Logical | 权限之间的判断关系,默认为Logical.AND |
示例1: 以下代码表示必须拥有product:brand:add
权限才可访问
@RequiresPermissions("product:brand:add")
public AjaxResult save(...)
{
return AjaxResult.success(...);
}
示例2: 以下代码表示必须拥有product:brand:add
和product:brand:edit
权限才可访问
@RequiresPermissions({"product:brand:add", "product:brand:edit"})
public AjaxResult save(...)
{
return AjaxResult.success(...);
}
示例3: 以下代码表示需要拥有product:brand:add
或product:brand:edit
权限才可访问
@RequiresPermissions(value = {"product:brand:add", "product:brand:edit"}, logical = Logical.OR)
public AjaxResult save(...)
{
return AjaxResult.success(...);
}
@RequiresRoles
注解用于配置接口要求用户拥有某(些)角色才可访问,它拥有两个参数
参数 | 类型 | 描述 |
---|---|---|
value | String[] | 角色列表 |
logical | Logical | 角色之间的判断关系,默认为Logical.AND |
示例1: 以下代码表示必须拥有admin
角色才可访问
@RequiresRoles("admin")
public AjaxResult save(...)
{
return AjaxResult.success(...);
}
示例2: 以下代码表示必须拥有admin
和productAdmin
角色才可访问
@RequiresRoles({"admin", "productAdmin"})
public AjaxResult save(...)
{
return AjaxResult.success(...);
}
示例3: 以下代码表示需要拥有admin
或productAdmin
角色才可访问
@RequiresRoles(value = {"admin", "common"}, logical = Logical.OR)
public AjaxResult save(...)
{
return AjaxResult.success(...);
}
@RequiresPermissions("product:brand:list")
@Operation(summary = "查询品牌列表")
@RequiresPermissions("product:brand:query")
@Operation(summary = "获取品牌详细信息")
@RequiresPermissions("product:brand:add")
@Operation(summary = "新增品牌")
@RequiresPermissions("product:brand:edit")
@Operation(summary = "修改品牌")
@RequiresPermissions("product:brand:remove")
@Operation(summary = "删除品牌")
注意:如果修改了角色权限,才需要重新登录用户账号,以便获取最新的角色权限信息
在swagger中直接测试,没有操作权限或未登录:
在前端发送的请求中获取请求头:
在Swagger中配置请求头,模拟账号登录:
再次测试,则可以成功访问接口。
以品牌管理为例,在需要被记录日志的controller
方法上添加@Log
注解,使用方法如下:
@Log(title = "品牌管理", businessType = BusinessType.INSERT)
@RequiresPermissions("product:brand:add")
@Operation(summary = "新增品牌")
@Log(title = "品牌管理", businessType = BusinessType.UPDATE)
@RequiresPermissions("product:brand:edit")
@Operation(summary = "修改品牌")
@Log(title = "品牌管理", businessType = BusinessType.DELETE)
@RequiresPermissions("product:brand:remove")
@Operation(summary = "删除品牌")
在后台系统的系统管理 => 日志管理
中查看操作日志:
若依系统实现了这部分功能,实现模块:spzx-common-log
。
LogAspect
负责解析日志注解Log
,调用AsyncLogService
利用异步方式保存日志。
1、在BusinessType
中新增业务操作类型如:
/**
* 测试
*/
TEST,
2、在sys_dict_data
字典数据表中初始化操作业务类型
选择操作类型:
添加字典数据:
3、在Controller
中使用注解
@Log(title = "测试", businessType = BusinessType.TEST)
@Operation(summary = "测试")
@DeleteMapping("/test")
public AjaxResult test() {
return success();
}