DukeDuke
主页
关于我们
主页
关于我们
  • 单体脚手架

    • 项目简介
    • 运行环境
    • 项目结构
    • 前端开发手册
    • 前端组件详解
    • 后端开发手册
    • 后端模块详解
    • 部署运维手册

Duke Admin 后端模块详解

目录

  • 模块概述
  • duke-admin 模块
  • duke-common 模块
  • duke-framework 模块
  • duke-system 模块
  • duke-monitor 模块
  • 模块开发规范

模块概述

Duke Admin 后端采用模块化设计,每个模块都有明确的职责和边界。模块之间通过依赖关系进行协作,遵循 DDD(领域驱动设计)分层架构原则。

模块架构图

duke-boot (父模块)
├── duke-admin          # 应用启动模块
├── duke-common         # 公共模块
├── duke-framework      # 框架核心模块
├── duke-system         # 系统管理模块
└── duke-monitor        # 监控模块

模块依赖关系

duke-admin
├── duke-common
├── duke-framework
├── duke-system
└── duke-monitor

duke-framework
└── duke-common

duke-system
├── duke-common
└── duke-framework

duke-monitor
├── duke-common
└── duke-framework

duke-admin 模块

模块概述

duke-admin 是应用的启动模块,负责应用的启动、配置管理和模块集成。

主要功能

  • 应用启动入口
  • 全局配置管理
  • 安全配置
  • 监控配置
  • 模块集成

核心类详解

1. DukeApplication 启动类

@SpringBootApplication
@EnableTransactionManagement
@MapperScan("com.duke.**.mapper")
public class DukeApplication {

    public static void main(String[] args) {
        SpringApplication.run(DukeApplication.class, args);
        System.out.println("(♥◠‿◠)ノ゙  Duke Admin 启动成功   ლ(´ڡ`ლ)゙");
    }
}

功能说明:

  • @SpringBootApplication: Spring Boot 应用注解
  • @EnableTransactionManagement: 启用事务管理
  • @MapperScan: MyBatis 映射器扫描

2. 配置类 (config/)

SecurityConfig 安全配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/auth/login").anonymous()
            .antMatchers("/doc.html", "/swagger-resources/**", "/webjars/**", "/v2/api-docs").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

功能说明:

  • 配置 JWT 认证
  • 配置权限控制
  • 配置密码加密
  • 配置跨域处理
SwaggerConfig API 文档配置
@Configuration
@EnableOpenApi
public class SwaggerConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
            .info(new Info()
                .title("Duke Admin API")
                .version("1.0.0")
                .description("Duke Admin 后台管理系统 API 文档")
                .contact(new Contact()
                    .name("Duke Team")
                    .email("duke@example.com")));
    }
}

功能说明:

  • 配置 Swagger/OpenAPI 文档
  • 设置 API 信息
  • 配置文档访问路径
RedisConfig Redis 配置
@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 设置序列化器
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);

        template.afterPropertiesSet();
        return template;
    }
}

功能说明:

  • 配置 Redis 连接
  • 设置序列化器
  • 启用缓存功能

配置文件

application.yml 主配置文件

server:
  port: 8080
  servlet:
    context-path: /

spring:
  application:
    name: duke-admin

  # 数据源配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/duke?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: password
    druid:
      initial-size: 5
      min-idle: 5
      max-active: 20
      max-wait: 60000

  # Redis 配置
  redis:
    host: localhost
    port: 6379
    password:
    database: 0
    timeout: 10s
    lettuce:
      pool:
        min-idle: 0
        max-idle: 8
        max-active: 8
        max-wait: -1ms

# MyBatis Plus 配置
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      logic-delete-field: delFlag
      logic-delete-value: 2
      logic-not-delete-value: 0

# JWT 配置
jwt:
  secret: duke-secret-key-2024
  expiration: 86400
  header: Authorization

# 日志配置
logging:
  level:
    com.duke: debug
    org.springframework.security: debug
  file:
    name: logs/duke-admin.log

duke-common 模块

模块概述

duke-common 是公共模块,提供各种通用功能和工具类,被其他所有模块依赖。

主要包结构

1. core/ 核心组件

// 基础实体类
@Data
@MappedSuperclass
public abstract class BaseEntity {
    @TableId(type = IdType.AUTO)
    private Long id;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableLogic
    private Integer delFlag;
}

// 统一响应结果
@Data
public class AjaxResult<T> {
    private Integer code;
    private String message;
    private T data;
    private Long timestamp;

    public static <T> AjaxResult<T> success() {
        return success(null);
    }

    public static <T> AjaxResult<T> success(T data) {
        AjaxResult<T> result = new AjaxResult<>();
        result.setCode(200);
        result.setMessage("操作成功");
        result.setData(data);
        result.setTimestamp(System.currentTimeMillis());
        return result;
    }

    public static <T> AjaxResult<T> error(String message) {
        AjaxResult<T> result = new AjaxResult<>();
        result.setCode(500);
        result.setMessage(message);
        result.setTimestamp(System.currentTimeMillis());
        return result;
    }
}

2. exception/ 异常处理

// 业务异常
public class BusinessException extends RuntimeException {
    private String code;

    public BusinessException(String message) {
        super(message);
        this.code = "500";
    }

    public BusinessException(String code, String message) {
        super(message);
        this.code = code;
    }
}

// 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    public AjaxResult<Void> handleBusinessException(BusinessException e) {
        return AjaxResult.error(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public AjaxResult<Void> handleValidationException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return AjaxResult.error("400", message);
    }

    @ExceptionHandler(Exception.class)
    public AjaxResult<Void> handleException(Exception e) {
        return AjaxResult.error("系统异常,请联系管理员");
    }
}

3. utils/ 工具类

// 字符串工具类
public class StringUtils {

    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    public static String camelToUnderscore(String str) {
        return str.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
    }
}

// 日期工具类
public class DateUtils {

    public static String format(LocalDateTime dateTime) {
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static LocalDateTime parse(String dateStr) {
        return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
}

// 加密工具类
public class EncryptUtils {

    public static String encryptPassword(String password) {
        return DigestUtils.md5DigestAsHex(password.getBytes());
    }

    public static boolean matches(String rawPassword, String encodedPassword) {
        return encryptPassword(rawPassword).equals(encodedPassword);
    }
}

4. cache/ 缓存相关

// 缓存管理器
@Component
public class CacheManager {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void set(String key, Object value, long timeout) {
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public void delete(String key) {
        redisTemplate.delete(key);
    }

    public boolean hasKey(String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }
}

5. validator/ 验证器

// 手机号验证器
public class PhoneValidator implements ConstraintValidator<Phone, String> {

    private static final String PHONE_PATTERN = "^1[3-9]\\d{9}$";

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (StringUtils.isEmpty(value)) {
            return true;
        }
        return value.matches(PHONE_PATTERN);
    }
}

// 手机号注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
    String message() default "手机号格式不正确";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

duke-framework 模块

模块概述

duke-framework 是框架核心模块,提供安全认证、JWT 处理、验证码等核心功能。

主要包结构

1. security/ 安全框架

// JWT 认证过滤器
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenProvider tokenProvider;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain filterChain) throws ServletException, IOException {
        try {
            String jwt = getJwtFromRequest(request);

            if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
                String username = tokenProvider.getUsernameFromToken(jwt);
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);

                UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception ex) {
            logger.error("Could not set user authentication in security context", ex);
        }

        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

// 用户详情服务
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }

        return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getPassword(),
            getAuthorities(user.getRoles())
        );
    }

    private Collection<? extends GrantedAuthority> getAuthorities(Set<Role> roles) {
        return roles.stream()
            .flatMap(role -> role.getPermissions().stream())
            .map(permission -> new SimpleGrantedAuthority(permission.getName()))
            .collect(Collectors.toList());
    }
}

2. token/ Token 处理

// JWT Token 提供者
@Component
public class JwtTokenProvider {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Value("${jwt.expiration}")
    private int jwtExpirationInMs;

    public String generateToken(Authentication authentication) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();

        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);

        return Jwts.builder()
            .setSubject(userDetails.getUsername())
            .setIssuedAt(new Date())
            .setExpiration(expiryDate)
            .signWith(SignatureAlgorithm.HS512, jwtSecret)
            .compact();
    }

    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
            .setSigningKey(jwtSecret)
            .parseClaimsJws(token)
            .getBody();

        return claims.getSubject();
    }

    public boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException ex) {
            logger.error("Invalid JWT signature");
        } catch (MalformedJwtException ex) {
            logger.error("Invalid JWT token");
        } catch (ExpiredJwtException ex) {
            logger.error("Expired JWT token");
        } catch (UnsupportedJwtException ex) {
            logger.error("Unsupported JWT token");
        } catch (IllegalArgumentException ex) {
            logger.error("JWT claims string is empty");
        }
        return false;
    }
}

3. code/ 验证码

// 验证码生成器
@Component
public class CaptchaGenerator {

    public CaptchaResult generateCaptcha() {
        // 生成随机验证码
        String code = generateRandomCode();

        // 生成验证码图片
        BufferedImage image = generateImage(code);

        // 转换为 Base64
        String base64Image = convertToBase64(image);

        return new CaptchaResult(code, base64Image);
    }

    private String generateRandomCode() {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }

    private BufferedImage generateImage(String code) {
        int width = 100;
        int height = 40;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();

        // 设置背景
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, width, height);

        // 设置字体
        g2d.setFont(new Font("Arial", Font.BOLD, 20));
        g2d.setColor(Color.BLACK);

        // 绘制验证码
        g2d.drawString(code, 20, 25);

        // 添加干扰线
        g2d.setColor(Color.LIGHT_GRAY);
        for (int i = 0; i < 5; i++) {
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            g2d.drawLine(x1, y1, x2, y2);
        }

        g2d.dispose();
        return image;
    }

    private String convertToBase64(BufferedImage image) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            byte[] bytes = baos.toByteArray();
            return Base64.getEncoder().encodeToString(bytes);
        } catch (IOException e) {
            throw new RuntimeException("Failed to convert image to base64", e);
        }
    }
}

duke-system 模块

模块概述

duke-system 是系统管理模块,采用 DDD 分层架构,提供用户管理、角色管理、菜单管理等核心业务功能。

DDD 分层结构

1. application/ 应用层

// 用户服务接口
public interface UserService {
    PageResult<UserVO> getUserList(UserQuery query);
    UserVO getUserById(Long id);
    void addUser(UserDTO userDTO);
    void updateUser(UserDTO userDTO);
    void deleteUser(Long[] ids);
    void resetPassword(Long userId, String newPassword);
}

// 用户服务实现
@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public PageResult<UserVO> getUserList(UserQuery query) {
        // 构建查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotEmpty(query.getUserName()), User::getUserName, query.getUserName())
               .eq(StringUtils.isNotEmpty(query.getStatus()), User::getStatus, query.getStatus())
               .orderByDesc(User::getCreateTime);

        // 分页查询
        Page<User> page = new Page<>(query.getPageNum(), query.getPageSize());
        Page<User> userPage = userRepository.selectPage(page, wrapper);

        // 转换为 VO
        List<UserVO> userVOList = userPage.getRecords().stream()
            .map(UserConverter.INSTANCE::entityToVO)
            .collect(Collectors.toList());

        return PageResult.of(userPage.getTotal(), userVOList);
    }

    @Override
    public void addUser(UserDTO userDTO) {
        // 验证用户名是否已存在
        User existingUser = userRepository.findByUsername(userDTO.getUserName());
        if (existingUser != null) {
            throw new BusinessException("用户名已存在");
        }

        // 创建用户实体
        User user = UserConverter.INSTANCE.dtoToEntity(userDTO);
        user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        user.setStatus("0"); // 正常状态

        userRepository.insert(user);
    }

    @Override
    public void updateUser(UserDTO userDTO) {
        User existingUser = userRepository.selectById(userDTO.getId());
        if (existingUser == null) {
            throw new BusinessException("用户不存在");
        }

        // 检查用户名是否被其他用户使用
        User userWithSameName = userRepository.findByUsername(userDTO.getUserName());
        if (userWithSameName != null && !userWithSameName.getId().equals(userDTO.getId())) {
            throw new BusinessException("用户名已存在");
        }

        User user = UserConverter.INSTANCE.dtoToEntity(userDTO);
        userRepository.updateById(user);
    }
}

2. domain/ 领域层

// 用户实体
@Data
@TableName("sys_user")
public class User extends BaseEntity {

    @TableField("user_name")
    private String userName;

    @TableField("nick_name")
    private String nickName;

    @TableField("email")
    private String email;

    @TableField("phone")
    private String phone;

    @TableField("password")
    private String password;

    @TableField("status")
    private String status;

    @TableField("dept_id")
    private Long deptId;

    @TableField("avatar")
    private String avatar;

    @TableField("login_ip")
    private String loginIp;

    @TableField("login_date")
    private LocalDateTime loginDate;

    @TableField("remark")
    private String remark;

    // 业务方法
    public boolean isEnabled() {
        return "0".equals(status);
    }

    public void enable() {
        this.status = "0";
    }

    public void disable() {
        this.status = "1";
    }

    public void updateLoginInfo(String loginIp) {
        this.loginIp = loginIp;
        this.loginDate = LocalDateTime.now();
    }
}

// 角色实体
@Data
@TableName("sys_role")
public class Role extends BaseEntity {

    @TableField("role_name")
    private String roleName;

    @TableField("role_key")
    private String roleKey;

    @TableField("role_sort")
    private Integer roleSort;

    @TableField("status")
    private String status;

    @TableField("remark")
    private String remark;

    // 关联关系
    @TableField(exist = false)
    private Set<Permission> permissions;

    // 业务方法
    public boolean hasPermission(String permissionName) {
        return permissions.stream()
            .anyMatch(permission -> permission.getName().equals(permissionName));
    }
}

// 权限实体
@Data
@TableName("sys_permission")
public class Permission extends BaseEntity {

    @TableField("permission_name")
    private String permissionName;

    @TableField("permission_key")
    private String permissionKey;

    @TableField("permission_type")
    private String permissionType;

    @TableField("status")
    private String status;

    @TableField("remark")
    private String remark;
}

3. infrastructure/ 基础设施层

// 用户仓储接口
public interface UserRepository extends BaseRepository<User> {
    User findByUsername(String username);
    User findByEmail(String email);
    List<User> findByDeptId(Long deptId);
    List<User> findByRoleId(Long roleId);
}

// 用户仓储实现
@Repository
public class UserRepositoryImpl extends BaseRepositoryImpl<User> implements UserRepository {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User findByUsername(String username) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserName, username);
        return userMapper.selectOne(wrapper);
    }

    @Override
    public User findByEmail(String email) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail, email);
        return userMapper.selectOne(wrapper);
    }

    @Override
    public List<User> findByDeptId(Long deptId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getDeptId, deptId);
        return userMapper.selectList(wrapper);
    }

    @Override
    public List<User> findByRoleId(Long roleId) {
        return userMapper.selectUsersByRoleId(roleId);
    }
}

// 用户 Mapper
@Mapper
public interface UserMapper extends BaseMapper<User> {

    @Select("SELECT u.* FROM sys_user u " +
            "INNER JOIN sys_user_role ur ON u.id = ur.user_id " +
            "WHERE ur.role_id = #{roleId}")
    List<User> selectUsersByRoleId(@Param("roleId") Long roleId);

    @Select("SELECT r.* FROM sys_role r " +
            "INNER JOIN sys_user_role ur ON r.id = ur.role_id " +
            "WHERE ur.user_id = #{userId}")
    List<Role> selectRolesByUserId(@Param("userId") Long userId);
}

数据传输对象 (DTO)

UserDTO

@Data
public class UserDTO {
    private Long id;

    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20, message = "用户名长度必须在2-20之间")
    private String userName;

    @NotBlank(message = "昵称不能为空")
    private String nickName;

    @Email(message = "邮箱格式不正确")
    private String email;

    @Phone
    private String phone;

    @Size(min = 6, max = 20, message = "密码长度必须在6-20之间")
    private String password;

    private Long deptId;
    private String avatar;
    private String remark;
    private Long[] roleIds;
}

UserQuery

@Data
public class UserQuery extends PageQuery {
    private String userName;
    private String nickName;
    private String email;
    private String phone;
    private String status;
    private Long deptId;
    private LocalDateTime beginTime;
    private LocalDateTime endTime;
}

UserVO

@Data
public class UserVO {
    private Long id;
    private String userName;
    private String nickName;
    private String email;
    private String phone;
    private String status;
    private Long deptId;
    private String deptName;
    private String avatar;
    private String loginIp;
    private LocalDateTime loginDate;
    private LocalDateTime createTime;
    private List<RoleVO> roles;
}

duke-monitor 模块

模块概述

duke-monitor 是系统监控模块,提供系统运行状态监控、在线用户管理、操作日志等功能。

主要功能

1. 在线用户监控

// 在线用户服务
@Service
public class OnlineUserService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String ONLINE_USER_KEY = "online_user:";

    public List<OnlineUser> getOnlineUserList() {
        Set<String> keys = redisTemplate.keys(ONLINE_USER_KEY + "*");
        List<OnlineUser> onlineUsers = new ArrayList<>();

        for (String key : keys) {
            OnlineUser user = (OnlineUser) redisTemplate.opsForValue().get(key);
            if (user != null) {
                onlineUsers.add(user);
            }
        }

        return onlineUsers;
    }

    public void forceLogout(String tokenId) {
        String key = ONLINE_USER_KEY + tokenId;
        redisTemplate.delete(key);
    }

    public void saveOnlineUser(String tokenId, OnlineUser user) {
        String key = ONLINE_USER_KEY + tokenId;
        redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
    }
}

// 在线用户实体
@Data
public class OnlineUser {
    private String tokenId;
    private String userName;
    private String nickName;
    private String ipaddr;
    private String browser;
    private String os;
    private LocalDateTime loginTime;
    private LocalDateTime lastAccessTime;
}

2. 操作日志

// 操作日志服务
@Service
public class OperLogService {

    @Autowired
    private OperLogMapper operLogMapper;

    public void saveOperLog(OperLog operLog) {
        operLogMapper.insert(operLog);
    }

    public PageResult<OperLog> getOperLogList(OperLogQuery query) {
        LambdaQueryWrapper<OperLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotEmpty(query.getTitle()), OperLog::getTitle, query.getTitle())
               .eq(StringUtils.isNotEmpty(query.getOperUser()), OperLog::getOperUser, query.getOperUser())
               .eq(StringUtils.isNotEmpty(query.getStatus()), OperLog::getStatus, query.getStatus())
               .between(query.getBeginTime() != null && query.getEndTime() != null,
                       OperLog::getOperTime, query.getBeginTime(), query.getEndTime())
               .orderByDesc(OperLog::getOperTime);

        Page<OperLog> page = new Page<>(query.getPageNum(), query.getPageSize());
        Page<OperLog> operLogPage = operLogMapper.selectPage(page, wrapper);

        return PageResult.of(operLogPage.getTotal(), operLogPage.getRecords());
    }

    public void cleanOperLog() {
        // 清理30天前的操作日志
        LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30);
        LambdaQueryWrapper<OperLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.lt(OperLog::getOperTime, thirtyDaysAgo);
        operLogMapper.delete(wrapper);
    }
}

// 操作日志实体
@Data
@TableName("sys_oper_log")
public class OperLog extends BaseEntity {

    @TableField("title")
    private String title;

    @TableField("method")
    private String method;

    @TableField("request_method")
    private String requestMethod;

    @TableField("operator_type")
    private String operatorType;

    @TableField("oper_user")
    private String operUser;

    @TableField("oper_url")
    private String operUrl;

    @TableField("oper_ip")
    private String operIp;

    @TableField("oper_location")
    private String operLocation;

    @TableField("oper_param")
    private String operParam;

    @TableField("json_result")
    private String jsonResult;

    @TableField("status")
    private String status;

    @TableField("error_msg")
    private String errorMsg;

    @TableField("oper_time")
    private LocalDateTime operTime;
}

3. 登录日志

// 登录日志服务
@Service
public class LoginLogService {

    @Autowired
    private LoginLogMapper loginLogMapper;

    public void saveLoginLog(LoginLog loginLog) {
        loginLogMapper.insert(loginLog);
    }

    public PageResult<LoginLog> getLoginLogList(LoginLogQuery query) {
        LambdaQueryWrapper<LoginLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotEmpty(query.getUserName()), LoginLog::getUserName, query.getUserName())
               .eq(StringUtils.isNotEmpty(query.getStatus()), LoginLog::getStatus, query.getStatus())
               .between(query.getBeginTime() != null && query.getEndTime() != null,
                       LoginLog::getLoginTime, query.getBeginTime(), query.getEndTime())
               .orderByDesc(LoginLog::getLoginTime);

        Page<LoginLog> page = new Page<>(query.getPageNum(), query.getPageSize());
        Page<LoginLog> loginLogPage = loginLogMapper.selectPage(page, wrapper);

        return PageResult.of(loginLogPage.getTotal(), loginLogPage.getRecords());
    }
}

// 登录日志实体
@Data
@TableName("sys_login_log")
public class LoginLog extends BaseEntity {

    @TableField("user_name")
    private String userName;

    @TableField("ipaddr")
    private String ipaddr;

    @TableField("login_location")
    private String loginLocation;

    @TableField("browser")
    private String browser;

    @TableField("os")
    private String os;

    @TableField("status")
    private String status;

    @TableField("msg")
    private String msg;

    @TableField("login_time")
    private LocalDateTime loginTime;
}

模块开发规范

1. 模块依赖规范

依赖原则

  • 上层模块可以依赖下层模块
  • 同层模块之间不能相互依赖
  • 避免循环依赖

依赖配置

<!-- duke-admin 模块依赖 -->
<dependencies>
    <dependency>
        <groupId>com.duke</groupId>
        <artifactId>duke-common</artifactId>
    </dependency>
    <dependency>
        <groupId>com.duke</groupId>
        <artifactId>duke-framework</artifactId>
    </dependency>
    <dependency>
        <groupId>com.duke</groupId>
        <artifactId>duke-system</artifactId>
    </dependency>
    <dependency>
        <groupId>com.duke</groupId>
        <artifactId>duke-monitor</artifactId>
    </dependency>
</dependencies>

2. 包命名规范

包命名规则

  • 使用小写字母
  • 使用点号分隔
  • 按功能模块划分
  • 遵循 DDD 分层架构

包结构示例

com.duke.system
├── application          # 应用层
│   ├── service         # 服务接口
│   ├── service.impl    # 服务实现
│   └── dto            # 数据传输对象
├── domain              # 领域层
│   ├── entity         # 领域实体
│   ├── service        # 领域服务
│   └── repository     # 仓储接口
└── infrastructure      # 基础设施层
    ├── repository     # 仓储实现
    ├── mapper         # 数据访问对象
    └── converter      # 对象转换器

3. 类命名规范

类命名规则

  • 使用 PascalCase
  • 类名要有意义
  • 遵循单一职责原则

命名示例

// 实体类
public class User { }
public class Role { }
public class Permission { }

// 服务类
public interface UserService { }
public class UserServiceImpl { }

// 仓储类
public interface UserRepository { }
public class UserRepositoryImpl { }

// 控制器类
public class UserController { }

// DTO 类
public class UserDTO { }
public class UserQuery { }
public class UserVO { }

4. 方法命名规范

方法命名规则

  • 使用 camelCase
  • 方法名要清晰表达功能
  • 遵循动词+名词的命名方式

命名示例

// 查询方法
public User findByUsername(String username);
public List<User> findByDeptId(Long deptId);
public PageResult<User> getUserList(UserQuery query);

// 保存方法
public void saveUser(User user);
public void addUser(UserDTO userDTO);
public void updateUser(UserDTO userDTO);

// 删除方法
public void deleteUser(Long id);
public void deleteUsers(Long[] ids);

// 业务方法
public void resetPassword(Long userId, String newPassword);
public void enableUser(Long userId);
public void disableUser(Long userId);

5. 异常处理规范

异常分类

  • BusinessException: 业务异常
  • ValidationException: 验证异常
  • SystemException: 系统异常

异常使用

// 业务异常
if (user == null) {
    throw new BusinessException("用户不存在");
}

// 验证异常
if (StringUtils.isEmpty(userName)) {
    throw new ValidationException("用户名不能为空");
}

// 系统异常
try {
    // 数据库操作
} catch (Exception e) {
    throw new SystemException("系统异常", e);
}

6. 日志规范

日志级别

  • ERROR: 错误信息
  • WARN: 警告信息
  • INFO: 一般信息
  • DEBUG: 调试信息

日志使用

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Override
    public void addUser(UserDTO userDTO) {
        log.info("开始添加用户: {}", userDTO.getUserName());

        try {
            // 业务逻辑
            log.info("用户添加成功: {}", userDTO.getUserName());
        } catch (Exception e) {
            log.error("用户添加失败: {}", userDTO.getUserName(), e);
            throw e;
        }
    }
}
最近更新:: 2025/8/14 09:20
Contributors: Duke
Prev
后端开发手册
Next
部署运维手册