第15章 - 最佳实践与常见问题

第15章 - 最佳实践与常见问题

15.1 开发最佳实践

15.1.1 代码规范

命名规范

类型 规范 示例
类名 大驼峰 SysUserController
方法名 小驼峰 getUserInfo
变量名 小驼峰 userName
常量名 全大写下划线 MAX_PAGE_SIZE
包名 全小写 com.ruoyi.system
数据库表名 小写下划线 sys_user
数据库字段 小写下划线 user_name

Controller层规范

@RestController
@RequestMapping("/user")
public class SysUserController extends BaseController {
    
    @Autowired
    private ISysUserService userService;
    
    /**
     * 查询用户列表
     * - 使用GET请求查询
     * - 使用@RequiresPermissions注解控制权限
     * - 返回TableDataInfo用于分页
     */
    @RequiresPermissions("system:user:list")
    @GetMapping("/list")
    public TableDataInfo list(SysUser user) {
        startPage();  // 开启分页
        List<SysUser> list = userService.selectUserList(user);
        return getDataTable(list);
    }
    
    /**
     * 新增用户
     * - 使用POST请求新增
     * - 使用@Log注解记录操作日志
     * - 使用@RequestBody接收JSON数据
     */
    @RequiresPermissions("system:user:add")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysUser user) {
        if (!userService.checkUserNameUnique(user)) {
            return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
        }
        user.setCreateBy(SecurityUtils.getUsername());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        return toAjax(userService.insertUser(user));
    }
    
    /**
     * 修改用户
     * - 使用PUT请求修改
     */
    @RequiresPermissions("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysUser user) {
        if (!userService.checkUserNameUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
        }
        user.setUpdateBy(SecurityUtils.getUsername());
        return toAjax(userService.updateUser(user));
    }
    
    /**
     * 删除用户
     * - 使用DELETE请求删除
     * - 支持批量删除
     */
    @RequiresPermissions("system:user:remove")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public AjaxResult remove(@PathVariable Long[] userIds) {
        if (ArrayUtils.contains(userIds, SecurityUtils.getUserId())) {
            return error("当前用户不能删除");
        }
        return toAjax(userService.deleteUserByIds(userIds));
    }
}

Service层规范

@Service
public class SysUserServiceImpl implements ISysUserService {
    
    @Autowired
    private SysUserMapper userMapper;
    
    @Autowired
    private SysRoleMapper roleMapper;
    
    /**
     * 1. 使用@Transactional管理事务
     * 2. 复杂业务使用事务注解
     * 3. 只读操作可以不加事务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUser(SysUser user) {
        // 新增用户信息
        int rows = userMapper.insertUser(user);
        // 新增用户与角色关联
        insertUserRole(user);
        return rows;
    }
    
    /**
     * 业务校验放在Service层
     */
    @Override
    public boolean checkUserNameUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkUserNameUnique(user.getUserName());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return false;
        }
        return true;
    }
}

15.1.2 安全规范

SQL注入防护

// 错误示例 - 存在SQL注入风险
@Select("SELECT * FROM sys_user WHERE user_name = '" + userName + "'")
SysUser selectByUserName(String userName);

// 正确示例 - 使用参数化查询
@Select("SELECT * FROM sys_user WHERE user_name = #{userName}")
SysUser selectByUserName(@Param("userName") String userName);

XSS防护

// 在Controller中使用@Validated验证输入
@PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user) {
    // ...
}

// 在实体类中使用@Xss注解
public class SysUser {
    @Xss(message = "用户昵称不能包含脚本字符")
    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
    private String nickName;
}

敏感数据处理

// 密码加密存储
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));

// 敏感字段脱敏返回
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;

// 或使用注解脱敏
@Sensitive(strategy = SensitiveStrategy.PHONE)
private String phone;

15.1.3 性能优化

数据库优化

// 1. 只查询需要的字段
<select id="selectUserList" resultMap="SysUserResult">
    select u.user_id, u.user_name, u.nick_name, u.status
    from sys_user u
</select>

// 2. 分页查询
startPage();  // 开启分页
List<SysUser> list = userService.selectUserList(user);

// 3. 合理使用索引
CREATE INDEX idx_user_name ON sys_user(user_name);
CREATE INDEX idx_status ON sys_user(status);

// 4. 避免N+1查询问题,使用关联查询
<select id="selectUserWithRole" resultMap="SysUserResult">
    select u.*, r.role_name
    from sys_user u
    left join sys_user_role ur on u.user_id = ur.user_id
    left join sys_role r on ur.role_id = r.role_id
</select>

缓存优化

// 使用Redis缓存热点数据
@Autowired
private RedisCache redisCache;

public SysUser selectUserByUserName(String userName) {
    String cacheKey = CacheConstants.SYS_USER_KEY + userName;
    SysUser user = redisCache.getCacheObject(cacheKey);
    if (user == null) {
        user = userMapper.selectUserByUserName(userName);
        redisCache.setCacheObject(cacheKey, user, 30, TimeUnit.MINUTES);
    }
    return user;
}

// 更新时删除缓存
public int updateUser(SysUser user) {
    int rows = userMapper.updateUser(user);
    if (rows > 0) {
        redisCache.deleteObject(CacheConstants.SYS_USER_KEY + user.getUserName());
    }
    return rows;
}

接口优化

// 1. 异步处理耗时操作
@Async
public void sendEmail(String email, String content) {
    // 发送邮件
}

// 2. 批量操作代替循环单条操作
// 错误示例
for (SysUser user : userList) {
    userMapper.insertUser(user);
}

// 正确示例
userMapper.batchInsertUser(userList);

// 3. 使用线程池处理并发请求
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(20);
    executor.setQueueCapacity(100);
    executor.setThreadNamePrefix("async-");
    executor.initialize();
    return executor;
}

15.2 常见问题解答

15.2.1 启动问题

Q1: 服务启动失败,提示Nacos连接失败

解决方案:
1. 确保Nacos服务已启动
2. 检查bootstrap.yml中Nacos地址配置
3. 检查防火墙是否开放8848端口
4. 确认Nacos中已导入相关配置文件

Q2: 服务启动后无法访问

解决方案:
1. 检查网关服务是否正常启动
2. 确认网关路由配置正确
3. 检查服务是否成功注册到Nacos
4. 查看服务日志是否有报错

Q3: 数据库连接失败

解决方案:
1. 检查MySQL服务是否启动
2. 确认数据库连接参数正确
3. 检查数据库用户权限
4. 确认防火墙开放3306端口

15.2.2 认证授权问题

Q4: 登录提示验证码错误

解决方案:
1. 确保Redis服务正常运行
2. 检查验证码是否过期
3. 清除浏览器缓存重新获取验证码
4. 检查Redis中是否存储了验证码

Q5: Token过期时间如何配置

# Nacos配置中心修改
security:
  # token过期时间(默认30分钟)
  expireTime: 30

Q6: 如何实现单点登录

1. 在认证中心记录用户Token
2. 新登录时使旧Token失效
3. 使用Redis存储Token与用户关系
4. 登录时检查并踢出旧会话

15.2.3 权限问题

Q7: 按钮权限不生效

解决方案:
1. 确认用户已分配对应角色
2. 确认角色已分配对应菜单权限
3. 检查权限标识是否正确
4. 清除前端缓存重新登录

Q8: 数据权限如何配置

// 1. 在Mapper.xml中使用数据权限过滤
<select id="selectUserList" resultMap="SysUserResult">
    select u.* from sys_user u
    <!-- 数据范围过滤 -->
    ${params.dataScope}
</select>

// 2. 在Service中添加数据权限注解
@DataScope(deptAlias = "d", userAlias = "u")
public List<SysUser> selectUserList(SysUser user) {
    return userMapper.selectUserList(user);
}

15.2.4 前端问题

Q9: 前端访问后端接口跨域

// vue.config.js配置代理
devServer: {
  proxy: {
    '/dev-api': {
      target: 'http://localhost:8080',
      changeOrigin: true,
      pathRewrite: {
        '^/dev-api': ''
      }
    }
  }
}

Q10: 菜单图标不显示

解决方案:
1. 确认图标名称正确
2. 使用Element Plus内置图标或SVG图标
3. 自定义图标需放在src/assets/icons/svg目录
4. 重新编译前端项目

15.2.5 部署问题

Q11: Docker部署MySQL数据丢失

# 使用数据卷持久化
volumes:
  - ./mysql/data:/var/lib/mysql

Q12: Nginx配置后刷新404

# 配置try_files
location / {
    root /home/ruoyi/projects/ruoyi-ui;
    try_files $uri $uri/ /index.html;
    index index.html index.htm;
}

Q13: 生产环境如何配置

# 生产环境建议配置
spring:
  profiles:
    active: prod
  datasource:
    dynamic:
      datasource:
        master:
          # 使用连接池
          druid:
            initial-size: 10
            min-idle: 10
            max-active: 100
            max-wait: 60000
            
# 日志级别调整
logging:
  level:
    com.ruoyi: warn

15.3 版本升级指南

15.3.1 升级步骤

1. 备份当前项目代码和数据库
2. 下载最新版本代码
3. 对比pom.xml依赖变化
4. 对比配置文件变化
5. 执行数据库升级脚本
6. 测试各功能模块
7. 部署上线

15.3.2 版本变更日志

关注官方发布说明:
- GitHub Releases
- 官方文档更新日志
- QQ群公告

15.4 总结

本章介绍了RuoYi-Cloud开发中的最佳实践和常见问题解决方案,包括:

  1. 代码规范:命名规范、Controller/Service层规范
  2. 安全规范:SQL注入、XSS防护、敏感数据处理
  3. 性能优化:数据库优化、缓存优化、接口优化
  4. 常见问题:启动、认证、权限、前端、部署问题
  5. 版本升级:升级步骤和注意事项

遵循这些最佳实践可以提高代码质量和系统稳定性,解决开发中遇到的常见问题。


上一章:二次开发指南 | 返回目录

附录:参考资源

官方资源

技术文档

社区资源

posted @ 2026-01-08 14:05  我才是银古  阅读(16)  评论(0)    收藏  举报