Duke Admin 后端模块详解
目录
模块概述
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;
}
}
}
