【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目,整合knef4j和mybaits实现基础用户信息管理
- 后端环境搭建
- 1.1 环境准备
- 1.2 数据库表准备
- 1.3 SpringBoot3项目创建
- 1.4 MySql环境整合,使用druid连接池
- 1.5 整合mybatis-plus
- 1.5.1 引入mybaties-plus
- 1.5.2 配置代码生成器
- 1.5.3 配置分页插件
- 1.6 整合swagger3(knife4j)
- 1.6.1 整合
- 1.6.2 使用
- 1.7 数据交互处理
- 1.7.1响应数据封装(公共返回数据类)
- 1.7.2 分页查询返回数据封装
- 1.8 全局异常处理
- 1.9 整合JWT,生成token
- 1.10 封装ThreadLocal工具类
- 1.11 MD5封装
- 1.12 登陆验证拦截
- 1.13 新增,登录和查询当前用户
- 1.13.1 新增用户
- 1.13.2 用户登录
- 1.13.3 获取当前用户信息
- 1.13.4 查询所有用户信息
- 1.14 删除和修改用户信息
- 1.14.1 删除用户信息
- 1.14.2 修改用户信息
跟着黑马敲了黑马点评和苍穹外卖,但是感觉黑马教程封装的太好了。于是想自己从零到一搭建一个前后端分离的简单项目。
主要参考的博客为:
从零搭建SpringBoot3+Vue3前后端分离项目基座,中小项目可用_springboot+vue3-CSDN博客
记录一下自己的实现过程。
最终实现效果如下:
后端环境搭建
1.1 环境准备
-spring-boot3 最低支持jdk17,所以需要准备jdk17的环境
-Idea版本 2024.1.4
-Mysql8
1.2 数据库表准备
可以随便使用一个数据库可视化软件,然后创建数据库data_demo,并运行以下查询,创建用户表
我用的是Navicat Premium
建好后,选中数据库,右键选择新建查询
运行如下命令,创建数据库表
CREATE TABLE user(id INT NOT NULL AUTO_INCREMENT COMMENT '主键',login_name VARCHAR(255) NOT NULL COMMENT '登录名(账号)',password VARCHAR(255) NOT NULL COMMENT '密码',name varchar(50) NOT NULL COMMENT '姓名',sex char(1) NOT NULL COMMENT '性别',phone VARCHAR(20) COMMENT '联系电话',PRIMARY KEY(id))COMMENT '用户信息表';
1.3 SpringBoot3项目创建
之后等待项目构建完成。构建完成的pom.xml文件如下,注意我在这里修改了spring的version,修改为3.3.3 ,因为在后面集成knef4j的时候发现3.4.0版本的spring无法显示接口。
参考博客如下:
尚硅谷新SSM教程中关于Knife4j 接口文档无法显示接口的问题_knife4j 识别不到controller-CSDN博客
即,正确的启动控制台没问题,但是不显示接口信息,后面将spring的版本降为3.3.3,成功解决
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.myProject</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><name>demo</name><description>demo</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
1.4 MySql环境整合,使用druid连接池
在pom.xml中添加jdbc依赖,防止项目启动时找不到Bean报错
<!--添加JDBC依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>
添加druid依赖
<!--添加Druid依赖--><!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-3-starter --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.20</version></dependency>
项目使用yml格式配置文件,修改resources下的application.properties为application.yml
,删除文件原本内容,并将application.yml文件内容加上如下
配置项目端口号
server:port: 9999
在application.yml
中配置数据源和druid连接池 ,注意将database的name修改为自己数据库的名称,以及mysql的username和password
# ???????
database:name: data_demospring:datasource: #????url: jdbc:mysql://localhost:3306/${database.name}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: root
启动项目, 查看日志,端口和druid 初始化, 整合成功
1.5 整合mybatis-plus
1.5.1 引入mybaties-plus
官网地址: https://baomidou.com/
- pom.xml中添加如下依赖
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-spring-boot3-starter -->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.5</version>
</dependency>
- application.yml中加入如下配置
# mybatis ??????
mybatis-plus:configuration:#????????map-underscore-to-camel-case: truemapper-locations: classpath:mapper/*.xmltype-aliases-package: com.example.demo
启动项目,出现mybatis-plus日志
1.5.2 配置代码生成器
- pom.xml中添加如下依赖
<!-- mybatis-plus 代码生成器-->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.5</version>
</dependency><!-- mybatis-plus代码生成器模板引擎 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency>
2.新建utils包,并在下边创建MybatisPlusGenerator.java代码生成器配置类
package com.example.demo.utils;import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;import java.io.File;
import java.sql.Types;
import java.util.Collections;public class MybatisPlusGenerator {static final String url = "jdbc:mysql://127.0.0.1:3306/data_demo?serverTimezone=UTC"; // 数据库地址static final String username = "root"; // 数据库用户名static final String password = "123456"; // 数据库密码static final String authorName = "HuaXiang"; // 作者名static final String parentPackageNameResource = "com/example/demo"; // mapper.xml路径static final String parentPackageNameJava = "com.example.demo"; // java 文件父包名// 要生成代码对应的数据表名static final String tableName = "user";public static void main(String[] args) {FastAutoGenerator.create(url, username, password)// 1.全局配置.globalConfig(builder -> {builder.author(authorName) // 设置作者.enableSpringdoc() // 开启 swagger 模式// 获取当前工程路径并定位到项目java目录下.outputDir(System.getProperty("user.dir") + "/src/main/java"); // 指定输出目录})// 2.数据源配置.dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {int typeCode = metaInfo.getJdbcType().TYPE_CODE;if (typeCode == Types.SMALLINT) {// 自定义类型转换return DbColumnType.INTEGER;}return typeRegistry.getColumnType(metaInfo);}))// 3.包名策略配置.packageConfig(builder -> {builder.parent(parentPackageNameJava) // 设置父包名.entity("entity").mapper("mapper").service("service").serviceImpl("service.impl").controller("controller")//.moduleName("system") // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/" + "/mapper")); // 设置mapperXml生成路径})// 策略配置.strategyConfig(builder -> {builder.addInclude(tableName) // 设置需要生成的表名// 覆盖已生成文件.entityBuilder().enableFileOverride().mapperBuilder().enableFileOverride().serviceBuilder().enableFileOverride().formatServiceFileName("%sService");//.addTablePrefix("t_", "c_"); // 设置过滤表前缀})// 配置模板.templateConfig(builder -> {//builder.controller(""); // 不生成controller}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
}
- 修改数据库相关信息
- 修改authorName
- 修改parentPackageNameResource, parentPackageNameJava
- 修改tableName, 要生成代码的数据表名称,多个表使用,分割
- .enableSpringdoc() 可以选择,生成swagger3文档注释
修改完成后运行main函数,生成相应代码,mapper.xml在resource下与java同路径下
运行后目录如下:
1.5.3 配置分页插件
新建config包,并在下边配置类MybatiesPlusConfig.java
package com.example.demo.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisPlusConfig {/*** 添加分页插件*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbTypereturn interceptor;}
}
在启动类配置扫描mapper路径@MapperScan(“com.example.demo.mapper”)
1.6 整合swagger3(knife4j)
1.6.1 整合
- pom.xml引入knife4j的依赖
<!-- API 文档 knife4j --><!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.5.0</version></dependency>
- application.yml中添加配置
# springdoc-openapi 配置
springdoc:swagger-ui:path: /swagger-ui.htmltags-sorter: alphaoperations-sorter: alphaapi-docs:path: /v3/api-docsgroup-configs:- group: 'default'paths-to-match: '/**'packages-to-scan: com.example.demo.controller# knife4j 配置
knife4j:# 是否启用增强enable: true# 开启生产环境屏蔽production: false# 是否认证登录basic:# basic是否开启,默认为falseenable: trueusername: rootpassword: 123456setting:language: zh_cnenable-version: trueenable-swagger-models: true
- 测试。配置完成后,访问路径:http://localhost:9999/doc.html ,用户名密码为配置文件中的用户名和密码,如图
1.6.2 使用
实体类使用@Schema注解,在mybatis-plus选择的话会自动生成
Controller层使用
/*** <p>* 用户信息表 前端控制器* </p>* @since 2024-12-06*/
@Tag(name = "用户接口")
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户列表分页* @param pageSize 每页显示的条数* @param currentPage 要查询的页* @param name 用户姓名* @return Result<PageResultBean<List<User>>>*/@GetMapping("/pageList")@Operation(summary = "用户列表分页查询")@Parameters({@Parameter(name = "Authorization", in = ParameterIn.HEADER, required = true, description = "token"),@Parameter(name = "pageSize", required = true, description = "每页显示的条数"),@Parameter(name = "currentPage", required = true, description = "要查询的页"),@Parameter(name = "name", description = "用户姓名", required = false)})public Result<PageResultBean<User>> pageList(@RequestParam int pageSize, @RequestParam int currentPage, @Nullable @RequestParam String name) {IPage<User> page = userService.pageList(pageSize, currentPage, name);if (page == null) {return Result.error("查询失败");}//PageResultBean<User> pageResultBean = new PageResultBean<User>(page.getTotal(), page.getRecords());return Result.success(PageResultBean.getInstance(page.getTotal(), page.getRecords()));}
}
1.7 数据交互处理
1.7.1响应数据封装(公共返回数据类)
封装返回数据封装类,放到common包下:
package com.example.demo.common;import io.swagger.v3.oas.annotations.media.Schema;public class Result<T> {@Schema(description = "业务状态码 1:成功 0: 失败")private int code; // 业务状态码 0:成功 1: 失败@Schema(description = "提示信息")private String message; // 提示信息@Schema(description = "返回数据")private T data; // 响应数据public Result(int code, String message, T data) {this.code = code;this.message = message;this.data = data;}// 操作成功返回响应结果(带响应数据)public static <E> Result<E> success(E data) {return new Result<>(1, "操作成功", data);}public static <E> Result<E> success() {return new Result<>(1, "操作成功", null);}public static <E> Result<E> error(String message) {return new Result<>(0, message, null);}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}@Overridepublic String toString() {return "Result{" +"code=" + code +", message='" + message + '\'' +", data=" + data +'}';}
}
1.7.2 分页查询返回数据封装
封装分页查询的数据,放到common包下
package com.example.demo.common;import io.swagger.v3.oas.annotations.media.Schema;public class Result<T> {@Schema(description = "业务状态码 0:成功 1: 失败")private int code; // 业务状态码 0:成功 1: 失败@Schema(description = "提示信息")private String message; // 提示信息@Schema(description = "返回数据")private T data; // 响应数据public Result(int code, String message, T data) {this.code = code;this.message = message;this.data = data;}// 操作成功返回响应结果(带响应数据)public static <E> Result<E> success(E data) {return new Result<>(0, "操作成功", data);}public static <E> Result<E> success() {return new Result<>(0, "操作成功", null);}public static <E> Result<E> error(String message) {return new Result<>(1, message, null);}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}@Overridepublic String toString() {return "Result{" +"code=" + code +", message='" + message + '\'' +", data=" + data +'}';}
}
1.8 全局异常处理
创建exception包,在包下放全局异常处理类GlobalExceptionHandler.java,
使用springboot @RestControllerAdvice注解配置
package com.example.demo.exception;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.example.demo.common.Result;// 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);@ExceptionHandler(Exception.class)public Result<String> handlerException(Exception e) {logger.warn(e.getMessage());return Result.error(StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "操作失败");}
}
1.9 整合JWT,生成token
- pom.xml 中引入依赖
<!-- jwt --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency>
- 封装工具类JwtUtil,放到utils包下
package com.example.demo.utils;import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;import java.util.Date;
import java.util.Map;public class JwtUtil {private static final String KEY = "Demo"; // 密钥// 接收数据,生成token并返回public static String getToken(Map<String, Object> claims) {return JWT.create().withClaim("claims", claims).withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 失效时间1小时.sign(Algorithm.HMAC256(KEY));}// 接收token,验证并返回数据public static Map<String, Object> parseToken(String token) {return JWT.require(Algorithm.HMAC256(KEY)).build().verify(token).getClaim("claims").asMap();}
}
1.10 封装ThreadLocal工具类
因为前后端分离,使用ThreadLocal线程变量存储用户登录信息,替代session
package com.example.demo.utils;public class ThreadLocalUtil {// 提供ThreadLocal 对象private static final ThreadLocal<Object> THREAD_LOCAL = new ThreadLocal<>();// 获取存储值public static <T> T get() {return (T) THREAD_LOCAL.get();}// 存储值public static void set(Object value) {THREAD_LOCAL.set(value);}// 清除THREAD_LOCAL 防止内存泄漏public static void remove() {THREAD_LOCAL.remove();}
}
1.11 MD5封装
package com.example.demo.utils;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public class Md5Util {/*** 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合*/protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};protected static MessageDigest messagedigest = null;static {try {messagedigest = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException nsaex) {System.err.println(Md5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");nsaex.printStackTrace();}}/*** 生成字符串的md5校验值** @param s* @return*/public static String getMD5String(String s) {return getMD5String(s.getBytes());}/*** 判断字符串的md5校验码是否与一个已知的md5码相匹配** @param password 要校验的字符串* @param md5PwdStr 已知的md5校验码* @return*/public static boolean checkPassword(String password, String md5PwdStr) {String s = getMD5String(password);return s.equals(md5PwdStr);}public static String getMD5String(byte[] bytes) {messagedigest.update(bytes);return bufferToHex(messagedigest.digest());}private static String bufferToHex(byte bytes[]) {return bufferToHex(bytes, 0, bytes.length);}private static String bufferToHex(byte bytes[], int m, int n) {StringBuffer stringbuffer = new StringBuffer(2 * n);int k = m + n;for (int l = m; l < k; l++) {appendHexPair(bytes[l], stringbuffer);}return stringbuffer.toString();}private static void appendHexPair(byte bt, StringBuffer stringbuffer) {char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>>// 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换stringbuffer.append(c0);stringbuffer.append(c1);}// 测试public static void main(String[] args) {System.out.println(Md5Util.getMD5String("admin"));}}
1.12 登陆验证拦截
- 创建包interceptors,在包下配置登录拦截器
package com.example.demo.interceptors;import com.example.demo.utils.JwtUtil;
import com.example.demo.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import java.util.Map;@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取tokenString token = request.getHeader("Authorization");// 验证tokentry {Map<String, Object> claims = JwtUtil.parseToken(token);// 存储业务信息到线程变量ThreadLocalUtil.set(claims);// 放行拦截return true;} catch (Exception e) {// 登录信息异常或未登录,http响应状态码为401response.setStatus(401);// 拦截请求return false;}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清除ThreadLocal业务数据ThreadLocalUtil.remove();}
}
- 在config包下创建WebConfig配置类,注册登录拦截器
package com.example.demo.config;import com.example.demo.interceptors.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.ArrayList;
import java.util.List;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 配置放行资源// 无需拦截的接口集合List<String> ignorePath = new ArrayList<>();// knife4j(swagger)ignorePath.add("/swagger-resources/**");ignorePath.add("/doc.html");ignorePath.add("/v3/**");ignorePath.add("/webjars/**");ignorePath.add("/static/**");ignorePath.add("/templates/**");ignorePath.add("/error");// 登录页面ignorePath.add("/user/login");ignorePath.add("/user/add");registry.addInterceptor(loginInterceptor).excludePathPatterns(ignorePath);}
}
1.13 新增,登录和查询当前用户
1.13.1 新增用户
逻辑为:
- 参数验证。对传入的user进行基本的非空校验,校验用户姓名,登录名以及密码是否为空或者null。为空则返回错误提示信息
- 用户名重复校验。通过userService中的
findByLoginName
去数据库中查询是否存在相同loginName的用户 - 密码非空判断,假如密码为空,设置为默认的123456
- 密码加密处理。使用1.11 中的MD5对数据库中的密码进行加密
- 保存用户信息到数据库,调用userService中的
add
方法。
在UserController.java中加入如下方法
/*** 添加用户* @param User* @return Result<String>*/@PostMapping("/add")@Operation(summary = "添加用户")@Parameter(name = "Authorization", in = ParameterIn.HEADER, required = true, description = "token")public Result<String> addUser(@RequestBody User user) {return userService.add(user);}
在UserService.java中加入如下方法
Result<String> add(User user);
UserServiceImpl.java中
package com.example.demo.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.utils.Md5Util;
import org.springframework.stereotype.Service;/*** <p>* 用户信息表 服务实现类* </p>** @author HuaXiang* @since 2024-12-06*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {private final UserMapper userMapper;public UserServiceImpl(UserMapper userMapper) {this.userMapper = userMapper;}public IPage<User> pageList(int pageSize, int currentPage, String name) {// 创建Page对象,传入当前页码和每页显示的记录数Page<User> page = new Page<>(currentPage, pageSize);// 可以在这里添加条件构造器来添加更复杂的查询条件,比如根据用户名模糊查询等// 以下是示例,如果name不为空进行模糊查询,实际根据需求调整if (name!= null &&!name.isEmpty()) {// 假设User实体类中有对应的username字段用于查询,此处只是示例,需根据实际调整LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.like(User::getName, name);return baseMapper.selectPage(page, queryWrapper);}// 如果没有额外条件,直接进行简单分页查询return baseMapper.selectPage(page, null);}@Overridepublic User findByLoginName(String loginName) {return userMapper.findByLoginName(loginName);}@Overridepublic Result<String> add(User user) {// 登录名校验if (user.getLoginName() == null || "".equals(user.getLoginName())) {return Result.error("登录名不能为空");}// 登录名重复校验if (findByLoginName(user.getLoginName()) != null) {return Result.error("登录名已存在,请重新输入");}if (user.getName() == null || "".equals(user.getName())) {return Result.error("姓名不能为空");}if (user.getPassword() == null || "".equals(user.getPassword())) {user.setPassword(Md5Util.getMD5String("123456"));}else{user.setPassword(Md5Util.getMD5String(user.getPassword()));}if (userMapper.insert(user) > 0) {return Result.success("添加成功");}return Result.error("添加失败");}
}
UserMapper.java中
package com.example.demo.mapper;import com.example.demo.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;/*** <p>* 用户信息表 Mapper 接口* </p>** @author HuaXiang* @since 2024-12-06*/
@Mapper
public interface UserMapper extends BaseMapper<User> {@Select("SELECT * FROM user WHERE login_name = #{loginName}")User findByLoginName(String loginName);}
使用swagger测试新增用户功能,在浏览器中输入http://localhost:9999/doc.html
请求参数如下:
{"loginName": "user1","password": "user1","name": "user1","sex": "男","phone": "15612341234"
}
数据库中查看,已经成功插入用户user1,密码也为user1
1.13.2 用户登录
- 接口定义:POST请求,路径为/login,
- 参数校验:对User对象判断,判断对象或则和loginName,password是否为空,为空则直接返回错误信息
- 用户名存在性校验调用userService.findByLoginName方法
- 密码正确性校验及登陆成功处理。
/*** 用户登录* @param user* @return*/@PostMapping("/login")@Operation(summary = "用户登录")@Parameters({@Parameter(name = "loginName", description = "登录名", required = true, schema = @Schema(type = "sting")),@Parameter(name = "password", description = "密码", required = true, schema = @Schema(type = "sting"))})public Result<String> login(@RequestBody User user) {if (user == null || "".equals(user.getLoginName()) || user.getLoginName() == null || "".equals(user.getPassword()) || user.getPassword() == null) {return Result.error("用户名密码不能为空");}// 检验用户名是否存在User eruser = userService.findByLoginName(user.getLoginName());if (eruser == null) {return Result.error("用户名不存在");}// 检验用户密码是否正确if (Md5Util.getMD5String(user.getPassword()).equals(eruser.getPassword())) {Map<String, Object> claims = new HashMap<>();claims.put("id", eruser.getId());claims.put("name", eruser.getName());claims.put("loginName", eruser.getLoginName());String token = JwtUtil.getToken(claims);return Result.success(token);}return Result.error("密码错误");}
测试
用刚刚新创建的用户测试用户登录功能。
1.13.3 获取当前用户信息
UserController.java
/*** 获取当前登录用户信息* @return User*/@GetMapping("/currentUser")@Operation(summary = "获取当前登录用户信息")@Parameter(name = "Authorization", in = ParameterIn.HEADER, required = true, description = "token")public Result<User> getCurrentUser() {Map<String, Object> userSession = ThreadLocalUtil.get();int id = (int) userSession.get("id");User user = userService.getUserById(id);if (user != null) {return Result.success(user);}return Result.error("用户状态异常");}
UserService.java
User getUserById(int id);
UserServiceImpl.java
@Overridepublic User getUserById(int id) {return userMapper.getUserById(id);}
UserMapper.java
@Select("SELECT * FROM user WHERE id = #{id}")User getUserById(int id);
测试,复制1.13.2中用户登录成功返回的token值作为请求头
1.13.4 查询所有用户信息
UserController.javas
/*** 查询所有用户信息* @return List<User>*/
@GetMapping("/userList")
@Operation(summary = "查询所有用户信息")
@Parameter(name = "Authorization", in = ParameterIn.HEADER, required = true, description = "token")
public Result<List<User>> userList() {List<User> userList = userService.getUserList();if (userList == null) {return Result.error("查询失败");}return Result.success(userList);
}
UserService.java
List<User> getUserList();
UserServiceImpl.java
/*** 查询所有用户信息* @return List<User>*/
@Override
public List<User> getUserList() {return userMapper.selectList(null);
}
1.14 删除和修改用户信息
1.14.1 删除用户信息
UserController.java
/*** 删除用户*/@DeleteMapping("/delete/{id}")@Operation(summary = "删除用户信息")@Parameters({@Parameter(name = "Authorization", in = ParameterIn.HEADER, required = true, description = "token"),@Parameter(name = "id", required = true, description = "用户id")})public Result<String> delete(@PathVariable int id) {boolean result = userService.deleteById(id); // 调用service层的方法根据loginname删除用户信息,这里假设UserService中有removeById方法if (result) {return Result.success("用户删除成功");} else {return Result.error("用户删除失败");}}
UserService.java
boolean deleteById(int id);
UserServiceImpl.java
@Overridepublic boolean deleteById(int id) {return userMapper.deleteById(id) > 0;}
测试
1.14.2 修改用户信息
UserController.java
@PutMapping("/update")@Operation(summary = "修改用户信息")@Parameter(name = "Authorization", in = ParameterIn.HEADER, required = true, description = "token")public Result<String> updateUser(@RequestBody User user) {Map<String, Object> userSession = ThreadLocalUtil.get();int id = (int) userSession.get("id");user.setId(id);user.setPassword(Md5Util.getMD5String(user.getPassword()));if (userService.update(user) > 0) {return Result.success("修改成功");}else {return Result.error("修改失败");}}
UserService.java
int update(User user);
UserServiceImpl.java
@Overridepublic int update(User user) {return userMapper.updateById(user);}
测试,先在请求头部中加上Authorization。(1.13.2中用户登录的返回的data)
请求参数如下:(将性别修改为女)
{"loginName": "user1","password": "user1","name": "user1","sex": "女","phone": "15612341234"
}