diff --git a/wm-base/src/main/java/com/water/base/config/MyBatisPlusConfig.java b/wm-base/src/main/java/com/water/base/config/MyBatisPlusConfig.java new file mode 100644 index 00000000..29e11807 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/config/MyBatisPlusConfig.java @@ -0,0 +1,18 @@ +package com.water.base.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MyBatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL)); + return interceptor; + } +} diff --git a/wm-base/src/main/java/com/water/base/config/SaTokenConfig.java b/wm-base/src/main/java/com/water/base/config/SaTokenConfig.java new file mode 100644 index 00000000..64ab8435 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/config/SaTokenConfig.java @@ -0,0 +1,25 @@ +package com.water.base.config; + +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.stp.StpUtil; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class SaTokenConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new SaInterceptor(handle -> { + // 放行认证接口 + SaRouter.match("/auth/**").stop(); + // 放行 Swagger + SaRouter.match("/swagger-ui/**").stop(); + SaRouter.match("/v3/api-docs/**").stop(); + // 其他需要登录 + SaRouter.match("/**").check(r -> StpUtil.checkLogin()); + })).addPathPatterns("/**"); + } +} diff --git a/wm-base/src/main/java/com/water/base/config/SwaggerConfig.java b/wm-base/src/main/java/com/water/base/config/SwaggerConfig.java new file mode 100644 index 00000000..ec3e0e55 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/config/SwaggerConfig.java @@ -0,0 +1,21 @@ +package com.water.base.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.Contact; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI waterOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("智慧水务管理系统 - 基础服务 API") + .description("系统管理:用户/角色/菜单/部门/日志") + .version("1.0.0") + .contact(new Contact().name("WM Team"))); + } +} diff --git a/wm-base/src/main/java/com/water/base/controller/AuthController.java b/wm-base/src/main/java/com/water/base/controller/AuthController.java new file mode 100644 index 00000000..373ceb37 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/controller/AuthController.java @@ -0,0 +1,52 @@ +package com.water.base.controller; + +import cn.dev33.satoken.stp.StpUtil; +import com.water.base.service.SysUserService; +import com.water.common.core.result.R; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import lombok.Data; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "认证管理") +@RestController +@RequestMapping("/auth") +@RequiredArgsConstructor +public class AuthController { + + private final SysUserService userService; + + @Data + public static class LoginRequest { + @NotBlank private String username; + @NotBlank private String password; + } + + @Operation(summary = "登录") + @PostMapping("/login") + public R login(@RequestBody LoginRequest req) { + String token = userService.login(req.getUsername(), req.getPassword()); + return R.ok(token); + } + + @Operation(summary = "登出") + @PostMapping("/logout") + public R logout() { + StpUtil.logout(); + return R.ok(); + } + + @Operation(summary = "获取当前用户信息") + @GetMapping("/user-info") + public R userInfo() { + return R.ok(userService.getLoginUser()); + } + + @Operation(summary = "验证token是否有效") + @GetMapping("/check") + public R check() { + return R.ok(StpUtil.isLogin()); + } +} diff --git a/wm-base/src/main/java/com/water/base/controller/SysDeptController.java b/wm-base/src/main/java/com/water/base/controller/SysDeptController.java new file mode 100644 index 00000000..e7fc052a --- /dev/null +++ b/wm-base/src/main/java/com/water/base/controller/SysDeptController.java @@ -0,0 +1,48 @@ +package com.water.base.controller; + +import com.water.base.entity.SysDept; +import com.water.base.service.SysDeptService; +import com.water.common.core.result.R; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name = "部门管理") +@RestController +@RequestMapping("/sys/dept") +@RequiredArgsConstructor +public class SysDeptController { + + private final SysDeptService sysDeptService; + + @Operation(summary = "部门树") + @GetMapping("/tree") + public R> tree() { + return R.ok(sysDeptService.buildDeptTree(sysDeptService.list())); + } + + @Operation(summary = "新增部门") + @PostMapping + public R create(@RequestBody SysDept dept) { + sysDeptService.save(dept); + return R.ok("创建成功"); + } + + @Operation(summary = "编辑部门") + @PutMapping("/{id}") + public R update(@PathVariable Long id, @RequestBody SysDept dept) { + dept.setId(id); + sysDeptService.updateById(dept); + return R.ok("更新成功"); + } + + @Operation(summary = "删除部门") + @DeleteMapping("/{id}") + public R delete(@PathVariable Long id) { + sysDeptService.removeById(id); + return R.ok("删除成功"); + } +} diff --git a/wm-base/src/main/java/com/water/base/controller/SysMenuController.java b/wm-base/src/main/java/com/water/base/controller/SysMenuController.java new file mode 100644 index 00000000..8eaabe0f --- /dev/null +++ b/wm-base/src/main/java/com/water/base/controller/SysMenuController.java @@ -0,0 +1,55 @@ +package com.water.base.controller; + +import com.water.base.entity.SysMenu; +import com.water.base.service.SysMenuService; +import com.water.common.core.result.R; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name = "菜单管理") +@RestController +@RequestMapping("/sys/menu") +@RequiredArgsConstructor +public class SysMenuController { + + private final SysMenuService sysMenuService; + + @Operation(summary = "菜单树") + @GetMapping("/tree") + public R> tree() { + List all = sysMenuService.list(); + return R.ok(sysMenuService.buildMenuTree(all)); + } + + @Operation(summary = "菜单列表(平铺)") + @GetMapping("/list") + public R> list() { + return R.ok(sysMenuService.list()); + } + + @Operation(summary = "新增菜单") + @PostMapping + public R create(@RequestBody SysMenu menu) { + sysMenuService.save(menu); + return R.ok("创建成功"); + } + + @Operation(summary = "编辑菜单") + @PutMapping("/{id}") + public R update(@PathVariable Long id, @RequestBody SysMenu menu) { + menu.setId(id); + sysMenuService.updateById(menu); + return R.ok("更新成功"); + } + + @Operation(summary = "删除菜单") + @DeleteMapping("/{id}") + public R delete(@PathVariable Long id) { + sysMenuService.removeById(id); + return R.ok("删除成功"); + } +} diff --git a/wm-base/src/main/java/com/water/base/controller/SysRoleController.java b/wm-base/src/main/java/com/water/base/controller/SysRoleController.java new file mode 100644 index 00000000..256fc959 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/controller/SysRoleController.java @@ -0,0 +1,54 @@ +package com.water.base.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.water.base.entity.SysRole; +import com.water.base.service.SysRoleService; +import com.water.common.core.result.R; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "角色管理") +@RestController +@RequestMapping("/sys/role") +@RequiredArgsConstructor +public class SysRoleController { + + private final SysRoleService sysRoleService; + + @Operation(summary = "角色列表") + @GetMapping("/list") + public R> list(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int size) { + return R.ok(sysRoleService.page(new Page<>(page, size))); + } + + @Operation(summary = "查询角色") + @GetMapping("/{id}") + public R getById(@PathVariable Long id) { + return R.ok(sysRoleService.getById(id)); + } + + @Operation(summary = "新增角色") + @PostMapping + public R create(@RequestBody SysRole role) { + sysRoleService.save(role); + return R.ok("创建成功"); + } + + @Operation(summary = "编辑角色") + @PutMapping("/{id}") + public R update(@PathVariable Long id, @RequestBody SysRole role) { + role.setId(id); + sysRoleService.updateById(role); + return R.ok("更新成功"); + } + + @Operation(summary = "删除角色") + @DeleteMapping("/{id}") + public R delete(@PathVariable Long id) { + sysRoleService.removeById(id); + return R.ok("删除成功"); + } +} diff --git a/wm-base/src/main/java/com/water/base/controller/SysUserController.java b/wm-base/src/main/java/com/water/base/controller/SysUserController.java new file mode 100644 index 00000000..eec58992 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/controller/SysUserController.java @@ -0,0 +1,63 @@ +package com.water.base.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.water.base.entity.SysUser; +import com.water.base.service.SysUserService; +import com.water.common.core.result.R; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "用户管理") +@RestController +@RequestMapping("/sys/user") +@RequiredArgsConstructor +public class SysUserController { + + private final SysUserService sysUserService; + + @Operation(summary = "分页查询用户") + @GetMapping("/list") + public R> list(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int size, + @RequestParam(required = false) String username) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + if (username != null && !username.isEmpty()) { + qw.like(SysUser::getUsername, username); + } + return R.ok(sysUserService.page(new Page<>(page, size), qw)); + } + + @Operation(summary = "获取用户详情") + @GetMapping("/{id}") + public R getById(@PathVariable Long id) { + return R.ok(sysUserService.getById(id)); + } + + @Operation(summary = "新增用户") + @PostMapping + public R create(@RequestBody SysUser user) { + sysUserService.save(user); + return R.ok("创建成功"); + } + + @Operation(summary = "编辑用户") + @PutMapping("/{id}") + public R update(@PathVariable Long id, @RequestBody SysUser user) { + user.setId(id); + sysUserService.updateById(user); + return R.ok("更新成功"); + } + + @Operation(summary = "启用/停用用户") + @PutMapping("/{id}/status") + public R toggleStatus(@PathVariable Long id, @RequestParam int status) { + SysUser user = new SysUser(); + user.setId(id); + user.setStatus(status); + sysUserService.updateById(user); + return R.ok(status == 1 ? "已启用" : "已停用"); + } +} diff --git a/wm-base/src/main/java/com/water/base/entity/SysDept.java b/wm-base/src/main/java/com/water/base/entity/SysDept.java new file mode 100644 index 00000000..65b913c4 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/entity/SysDept.java @@ -0,0 +1,26 @@ +package com.water.base.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@TableName("sys_dept") +public class SysDept { + @TableId(type = IdType.AUTO) + private Long id; + private Long parentId; + private String deptName; + private String deptType; + private Integer sortOrder; + private String leader; + private String phone; + private Integer status; + @TableLogic + private Integer deleted; + @TableField(exist = false) + private List children; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/wm-base/src/main/java/com/water/base/entity/SysMenu.java b/wm-base/src/main/java/com/water/base/entity/SysMenu.java new file mode 100644 index 00000000..d66ecdd7 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/entity/SysMenu.java @@ -0,0 +1,29 @@ +package com.water.base.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@TableName("sys_menu") +public class SysMenu { + @TableId(type = IdType.AUTO) + private Long id; + private Long parentId; + private String menuName; + private String menuType; + private String path; + private String component; + private String perms; + private String icon; + private Integer sortOrder; + private Integer visible; + private Integer status; + @TableLogic + private Integer deleted; + @TableField(exist = false) + private List children; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/wm-base/src/main/java/com/water/base/entity/SysRole.java b/wm-base/src/main/java/com/water/base/entity/SysRole.java new file mode 100644 index 00000000..af7fca41 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/entity/SysRole.java @@ -0,0 +1,22 @@ +package com.water.base.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@TableName("sys_role") +public class SysRole { + @TableId(type = IdType.AUTO) + private Long id; + private String roleName; + private String roleKey; + private Integer roleSort; + private String dataScope; + private Integer status; + private String remark; + @TableLogic + private Integer deleted; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/wm-base/src/main/java/com/water/base/entity/SysUser.java b/wm-base/src/main/java/com/water/base/entity/SysUser.java new file mode 100644 index 00000000..d1d34e97 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/entity/SysUser.java @@ -0,0 +1,29 @@ +package com.water.base.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@TableName("sys_user") +public class SysUser { + @TableId(type = IdType.AUTO) + private Long id; + private Long deptId; + private String username; + private String password; + private String realName; + private String nickname; + private String phone; + private String email; + private String avatar; + private Integer gender; + private String roleType; + private Integer status; + private String loginIp; + private LocalDateTime loginAt; + @TableLogic + private Integer deleted; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/wm-base/src/main/java/com/water/base/mapper/SysDeptMapper.java b/wm-base/src/main/java/com/water/base/mapper/SysDeptMapper.java new file mode 100644 index 00000000..3cef6115 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/mapper/SysDeptMapper.java @@ -0,0 +1,8 @@ +package com.water.base.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.base.entity.SysDept; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysDeptMapper extends BaseMapper {} diff --git a/wm-base/src/main/java/com/water/base/mapper/SysMenuMapper.java b/wm-base/src/main/java/com/water/base/mapper/SysMenuMapper.java new file mode 100644 index 00000000..f31768d8 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/mapper/SysMenuMapper.java @@ -0,0 +1,13 @@ +package com.water.base.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.base.entity.SysMenu; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import java.util.List; + +@Mapper +public interface SysMenuMapper extends BaseMapper { + @Select("SELECT m.* FROM sys_menu m INNER JOIN sys_role_menu rm ON m.id = rm.menu_id WHERE rm.role_id = #{roleId} AND m.status = 1 AND m.visible = 1 ORDER BY m.sort_order") + List selectMenusByRoleId(Long roleId); +} diff --git a/wm-base/src/main/java/com/water/base/mapper/SysRoleMapper.java b/wm-base/src/main/java/com/water/base/mapper/SysRoleMapper.java new file mode 100644 index 00000000..99318a3c --- /dev/null +++ b/wm-base/src/main/java/com/water/base/mapper/SysRoleMapper.java @@ -0,0 +1,8 @@ +package com.water.base.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.base.entity.SysRole; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysRoleMapper extends BaseMapper {} diff --git a/wm-base/src/main/java/com/water/base/mapper/SysUserMapper.java b/wm-base/src/main/java/com/water/base/mapper/SysUserMapper.java new file mode 100644 index 00000000..e93e8c05 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/mapper/SysUserMapper.java @@ -0,0 +1,16 @@ +package com.water.base.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.base.entity.SysUser; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import java.util.List; + +@Mapper +public interface SysUserMapper extends BaseMapper { + @Select("SELECT r.role_key FROM sys_role r INNER JOIN sys_user_role ur ON r.id = ur.role_id WHERE ur.user_id = #{userId} AND r.status = 1") + List selectRoleKeysByUserId(Long userId); + + @Select("SELECT r.data_scope FROM sys_role r INNER JOIN sys_user_role ur ON r.id = ur.role_id WHERE ur.user_id = #{userId} AND r.status = 1 ORDER BY r.role_sort LIMIT 1") + String selectDataScopeByUserId(Long userId); +} diff --git a/wm-base/src/main/java/com/water/base/service/SysDeptService.java b/wm-base/src/main/java/com/water/base/service/SysDeptService.java new file mode 100644 index 00000000..f0a2e6b0 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/service/SysDeptService.java @@ -0,0 +1,23 @@ +package com.water.base.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.water.base.entity.SysDept; +import com.water.base.mapper.SysDeptMapper; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class SysDeptService extends ServiceImpl { + + public List buildDeptTree(List depts) { + Map> parentMap = depts.stream() + .collect(Collectors.groupingBy(d -> d.getParentId() == null ? 0L : d.getParentId())); + List roots = parentMap.getOrDefault(0L, Collections.emptyList()); + for (SysDept root : roots) { + root.setChildren(parentMap.getOrDefault(root.getId(), Collections.emptyList())); + } + return roots; + } +} diff --git a/wm-base/src/main/java/com/water/base/service/SysMenuService.java b/wm-base/src/main/java/com/water/base/service/SysMenuService.java new file mode 100644 index 00000000..569e977d --- /dev/null +++ b/wm-base/src/main/java/com/water/base/service/SysMenuService.java @@ -0,0 +1,30 @@ +package com.water.base.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.water.base.entity.SysMenu; +import com.water.base.mapper.SysMenuMapper; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class SysMenuService extends ServiceImpl { + + /** + * 构建菜单树 + */ + public List buildMenuTree(List menus) { + Map> parentMap = menus.stream() + .collect(Collectors.groupingBy(m -> m.getParentId() == null ? 0L : m.getParentId())); + List roots = parentMap.getOrDefault(0L, Collections.emptyList()); + for (SysMenu root : roots) { + root.setChildren(parentMap.getOrDefault(root.getId(), Collections.emptyList())); + } + return roots; + } + + public List getMenusByRoleId(Long roleId) { + return baseMapper.selectMenusByRoleId(roleId); + } +} diff --git a/wm-base/src/main/java/com/water/base/service/SysRoleService.java b/wm-base/src/main/java/com/water/base/service/SysRoleService.java new file mode 100644 index 00000000..12da57bc --- /dev/null +++ b/wm-base/src/main/java/com/water/base/service/SysRoleService.java @@ -0,0 +1,9 @@ +package com.water.base.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.water.base.entity.SysRole; +import com.water.base.mapper.SysRoleMapper; +import org.springframework.stereotype.Service; + +@Service +public class SysRoleService extends ServiceImpl {} diff --git a/wm-base/src/main/java/com/water/base/service/SysUserService.java b/wm-base/src/main/java/com/water/base/service/SysUserService.java new file mode 100644 index 00000000..63655a80 --- /dev/null +++ b/wm-base/src/main/java/com/water/base/service/SysUserService.java @@ -0,0 +1,42 @@ +package com.water.base.service; + +import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.water.base.entity.SysUser; +import com.water.base.mapper.SysUserMapper; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class SysUserService extends ServiceImpl { + + /** + * 登录验证 + */ + public String login(String username, String password) { + SysUser user = this.getOne(new LambdaQueryWrapper() + .eq(SysUser::getUsername, username) + .eq(SysUser::getStatus, 1)); + if (user == null) { + throw new RuntimeException("用户名或密码错误"); + } + if (!BCrypt.checkpw(password, user.getPassword())) { + throw new RuntimeException("用户名或密码错误"); + } + // 登录成功,创建token + StpUtil.login(user.getId()); + // 获取用户角色权限列表 + List roleKeys = baseMapper.selectRoleKeysByUserId(user.getId()); + StpUtil.getSession().set("roleKeys", roleKeys); + StpUtil.getSession().set("realName", user.getRealName()); + return StpUtil.getTokenValue(); + } + + public SysUser getLoginUser() { + long userId = StpUtil.getLoginIdAsLong(); + return this.getById(userId); + } +} diff --git a/wm-common/pom.xml b/wm-common/pom.xml index b9bd32ec..6213ec1d 100644 --- a/wm-common/pom.xml +++ b/wm-common/pom.xml @@ -11,5 +11,7 @@ com.github.xiaoyminknife4j-openapi3-jakarta-spring-boot-starter cn.hutoolhutool-all com.alibabaeasyexcel - - \ No newline at end of file + org.springframework.bootspring-boot-starter-validation + + +