feat(admin-server): 添加管理员相关功能
- 新增 Admin 实体类 - 添加 AdminMapper 接口及 XML 配置 - 实现 AdminService 接口及其实现类 - 创建 AdminController 控制器 - 增加全局异常处理器和统一返回结果封装 - 集成 MyBatis-Plus 和 Swagger
This commit is contained in:
parent
3b12e9ece2
commit
8e3e8fc8b8
10
pom.xml
10
pom.xml
|
|
@ -44,6 +44,11 @@
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-boot-starter</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.xiaoymin</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
|
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
|
||||||
|
|
@ -54,6 +59,11 @@
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
<version>3.5.12</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
package com.example.admin_server;
|
package com.example.admin_server;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@MapperScan("com.example.admin_server.mapper")
|
||||||
public class AdminServerApplication {
|
public class AdminServerApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
package com.example.admin_server.common;
|
||||||
|
|
||||||
|
import com.example.admin_server.enums.ResultCode;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import javax.validation.ConstraintViolation;
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理器,统一将异常转换为 Result 返回
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数校验异常(@Valid)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
|
||||||
|
String message = ex.getBindingResult().getFieldErrors().stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(err -> err.getField() + " " + err.getDefaultMessage())
|
||||||
|
.orElse(ResultCode.VALIDATE_ERROR.getMsg());
|
||||||
|
log.warn("@Valid参数校验失败: {}", message);
|
||||||
|
return Result.of(ResultCode.VALIDATE_ERROR, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数绑定异常(普通对象绑定)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(BindException.class)
|
||||||
|
public Result<?> handleBindException(BindException ex) {
|
||||||
|
String message = ex.getFieldErrors().stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(err -> err.getField() + " " + err.getDefaultMessage())
|
||||||
|
.orElse(ResultCode.VALIDATE_ERROR.getMsg());
|
||||||
|
log.warn("参数绑定失败: {}", message);
|
||||||
|
return Result.of(ResultCode.VALIDATE_ERROR, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单个参数校验(@Validated)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(ConstraintViolationException.class)
|
||||||
|
public Result<?> handleConstraintViolationException(ConstraintViolationException ex) {
|
||||||
|
String message = ex.getConstraintViolations().stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(ConstraintViolation::getMessage)
|
||||||
|
.orElse(ResultCode.VALIDATE_ERROR.getMsg());
|
||||||
|
log.warn("@Validated参数校验失败: {}", message);
|
||||||
|
return Result.of(ResultCode.VALIDATE_ERROR, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求体不可读
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||||
|
public Result<?> handleHttpMessageNotReadable(HttpMessageNotReadableException ex) {
|
||||||
|
log.warn("消息不可读: {}", ex.getMessage());
|
||||||
|
return Result.of(ResultCode.VALIDATE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兜底异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public Result<?> handleException(Exception ex) {
|
||||||
|
log.error("系统异常", ex);
|
||||||
|
return Result.of(ResultCode.SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.example.admin_server.common;
|
||||||
|
|
||||||
|
import com.example.admin_server.enums.ResultCode;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Result<T> {
|
||||||
|
|
||||||
|
private Integer code;
|
||||||
|
private String msg;
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
private Result() {}
|
||||||
|
|
||||||
|
/** 成功:无数据 */
|
||||||
|
public static <T> Result<T> ok() {
|
||||||
|
return restResult(null, ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 成功:有数据 */
|
||||||
|
public static <T> Result<T> ok(T data) {
|
||||||
|
return restResult(data, ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 成功:指定 msg 和 data */
|
||||||
|
public static <T> Result<T> ok(String msg, T data) {
|
||||||
|
return restResult(data, ResultCode.SUCCESS.getCode(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 失败:默认错误码与信息 */
|
||||||
|
public static <T> Result<T> fail() {
|
||||||
|
return restResult(null, ResultCode.FAIL.getCode(), ResultCode.FAIL.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 失败:指定信息 */
|
||||||
|
public static <T> Result<T> fail(String msg) {
|
||||||
|
return restResult(null, ResultCode.FAIL.getCode(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 失败:指定错误码与信息 */
|
||||||
|
public static <T> Result<T> fail(Integer code, String msg) {
|
||||||
|
return restResult(null, code, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 通用:使用枚举返回 */
|
||||||
|
public static <T> Result<T> of(ResultCode resultCode) {
|
||||||
|
return restResult(null, resultCode.getCode(), resultCode.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 通用:使用枚举 + 自定义提示 */
|
||||||
|
public static <T> Result<T> of(ResultCode resultCode, String msg) {
|
||||||
|
return restResult(null, resultCode.getCode(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 通用:使用枚举 + 返回数据 */
|
||||||
|
public static <T> Result<T> of(ResultCode resultCode, T data) {
|
||||||
|
return restResult(data, resultCode.getCode(), resultCode.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 统一创建返回结构 */
|
||||||
|
private static <T> Result<T> restResult(T data, int code, String msg) {
|
||||||
|
Result<T> result = new Result<>();
|
||||||
|
result.setCode(code);
|
||||||
|
result.setMsg(msg);
|
||||||
|
result.setData(data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否成功 */
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return this.code != null && this.code.equals(ResultCode.SUCCESS.getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.example.admin_server.controller.admin;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 后台管理员表 前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin")
|
||||||
|
public class AdminController {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.example.admin_server.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ResultCode {
|
||||||
|
|
||||||
|
SUCCESS(200, "成功"),
|
||||||
|
FAIL(500, "失败"),
|
||||||
|
UNAUTHORIZED(401, "未授权"),
|
||||||
|
FORBIDDEN(403, "禁止访问"),
|
||||||
|
NOT_FOUND(404, "资源不存在"),
|
||||||
|
VALIDATE_ERROR(400, "参数校验失败"),
|
||||||
|
SERVER_ERROR(503, "服务器内部错误");
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
private final String msg;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.admin_server.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.example.admin_server.model.entity.Admin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 后台管理员表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
public interface AdminMapper extends BaseMapper<Admin> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
package com.example.admin_server.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 后台管理员表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("admin")
|
||||||
|
@ApiModel(value="Admin对象", description="后台管理员表")
|
||||||
|
public class Admin implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户名")
|
||||||
|
@TableField("username")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "密码")
|
||||||
|
@TableField("password")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "姓名")
|
||||||
|
@TableField("real_name")
|
||||||
|
private String realName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "邮箱")
|
||||||
|
@TableField("email")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机号")
|
||||||
|
@TableField("phone")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "头像")
|
||||||
|
@TableField("avatar")
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "状态:0禁用,1正常")
|
||||||
|
@TableField("status")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否为超级管理员:1是,0否")
|
||||||
|
@TableField("is_super")
|
||||||
|
private Integer isSuper;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "上次登录IP")
|
||||||
|
@TableField("last_login_ip")
|
||||||
|
private String lastLoginIp;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "上次登录时间")
|
||||||
|
@TableField("last_login_time")
|
||||||
|
private LocalDateTime lastLoginTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
@TableField("create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "更新时间")
|
||||||
|
@TableField("update_time")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.admin_server.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.example.admin_server.model.entity.Admin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 后台管理员表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
public interface IAdminService extends IService<Admin> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.example.admin_server.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.example.admin_server.mapper.AdminMapper;
|
||||||
|
import com.example.admin_server.model.entity.Admin;
|
||||||
|
import com.example.admin_server.service.IAdminService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 后台管理员表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.example.admin_server.mapper.AdminMapper">
|
||||||
|
|
||||||
|
<!-- 通用查询映射结果 -->
|
||||||
|
<resultMap id="BaseResultMap" type="com.example.admin_server.model.entity.Admin">
|
||||||
|
<id column="id" property="id" />
|
||||||
|
<result column="username" property="username" />
|
||||||
|
<result column="password" property="password" />
|
||||||
|
<result column="real_name" property="realName" />
|
||||||
|
<result column="email" property="email" />
|
||||||
|
<result column="phone" property="phone" />
|
||||||
|
<result column="avatar" property="avatar" />
|
||||||
|
<result column="status" property="status" />
|
||||||
|
<result column="is_super" property="isSuper" />
|
||||||
|
<result column="last_login_ip" property="lastLoginIp" />
|
||||||
|
<result column="last_login_time" property="lastLoginTime" />
|
||||||
|
<result column="create_time" property="createTime" />
|
||||||
|
<result column="update_time" property="updateTime" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue