第 3 章 实战项目 1:通用用户管理后端(接单高频需求)

用户管理是 Java 后端接单中最常见的基础需求 ------ 不管是小程序、企业管理系统,还是电商后台,几乎都离不开 "用户注册、登录、权限校验" 核心功能。这一章我会带你从零开发一个可直接接单复用的用户管理后端,包含完整代码、测试步骤和交付技巧,做完就能放进作品集,直接对接客户需求。


一、需求分析(接单时这么跟客户确认)

功能模块 具体需求 技术实现
用户注册 手机号 / 用户名 + 密码注册,验证码校验,密码加密 Spring Boot + MD5 加密 + Redis 存验证码
用户登录 账号密码登录,生成 JWT 令牌返回 JWT + Spring Security(轻量版)
信息管理 查询用户信息、修改密码、修改个人资料 MyBatis + MySQL CRUD
权限校验 接口级权限控制(普通用户 / 管理员) JWT 解析 + 自定义注解


二、项目搭建(10 分钟搞定骨架)

  1. IDEA 新建 Spring Boot 项目

• 项目名:user-admin-api

• 依赖选择:Spring Web + MyBatis Framework + MySQL Driver + Redis Starter + Lombok

• JDK 版本:17(和上一章环境一致)

  1. 核心配置文件(application.yml)

直接复制以下配置,仅需修改数据库密码为你自己的:

复制代码
server:
  port: 8080 # 项目端口

spring:
  # 数据库配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/user_admin?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: your_mysql_password # 替换为你的MySQL密码
  # Redis配置
  redis:
    host: localhost
    port: 6379
    password: '' # 无密码留空
    database: 0

# MyBatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml # Mapper文件路径
  type-aliases-package: com.example.useradminapi.entity # 实体类包名
  configuration:
    map-underscore-to-camel-case: true # 下划线转驼峰

# JWT配置(自定义)
jwt:
  secret: your_jwt_secret_123456 # 自定义密钥,接单时换成随机字符串
  expire: 86400000 # 令牌过期时间(24小时,单位毫秒)
  1. 数据库表设计(直接执行 SQL)

新建数据库user_admin,执行以下 SQL 创建用户表:

复制代码
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) NOT NULL COMMENT '加密密码',
  `phone` varchar(20) DEFAULT NULL COMMENT '手机号',
  `nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
  `role` varchar(20) DEFAULT 'USER' COMMENT '角色:ADMIN/USER',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`),
  UNIQUE KEY `uk_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

三、核心代码实现(全注释,直接复制)

  1. 实体类(Entity)

新建com.example.useradminapi.entity.SysUser:

复制代码
import lombok.Data;
import java.time.LocalDateTime;

/**
 * 用户实体类
 */
@Data // Lombok简化get/set
public class SysUser {
    private Long id; // 用户ID
    private String username; // 用户名
    private String password; // 加密密码
    private String phone; // 手机号
    private String nickname; // 昵称
    private String role; // 角色:ADMIN/USER
    private LocalDateTime createTime; // 创建时间
}
  1. 工具类(加密 + JWT)

(1)MD5 加密工具(com.example.useradminapi.util.Md5Util

复制代码
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5加密工具(密码加密用)
 */
public class Md5Util {
    // 盐值,增强加密安全性
    private static final String SALT = "user_admin_123";

    public static String encrypt(String password) {
        try {
            // 拼接盐值
            String str = password + SALT;
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes());
            byte[] byteDigest = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < byteDigest.length; offset++) {
                i = byteDigest[offset];
                if (i < 0) i += 256;
                if (i < 16) buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            // 32位加密
            return buf.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }
}

(2)JWT 工具(com.example.useradminapi.util.JwtUtil

复制代码
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;

/**
 * JWT令牌工具类(登录返回令牌、接口校验用)
 */
@Component
public class JwtUtil {
    // 从配置文件读取密钥
    @Value("${jwt.secret}")
    private String secret;
    // 令牌过期时间
    @Value("${jwt.expire}")
    private Long expire;

    /**
     * 生成JWT令牌
     */
    public String generateToken(Long userId, String username, String role) {
        // 生成密钥
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
        // 构建令牌
        return Jwts.builder()
                .claim("userId", userId) // 存入用户ID
                .claim("username", username) // 存入用户名
                .claim("role", role) // 存入角色
                .setExpiration(new Date(System.currentTimeMillis() + expire)) // 过期时间
                .signWith(key) // 签名
                .compact();
    }

    /**
     * 解析JWT令牌,获取Claims
     */
    public Claims parseToken(String token) {
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}
  1. Mapper 层(数据访问)

(1)Mapper 接口(com.example.useradminapi.mapper.SysUserMapper

复制代码
import com.example.useradminapi.entity.SysUser;
import org.apache.ibatis.annotations.*;

/**
 * 用户Mapper接口
 */
@Mapper // 标识为MyBatis Mapper
public interface SysUserMapper {
    // 根据用户名查询用户
    @Select("select * from sys_user where username = #{username}")
    SysUser selectByUsername(String username);

    // 根据手机号查询用户
    @Select("select * from sys_user where phone = #{phone}")
    SysUser selectByPhone(String phone);

    // 新增用户
    @Insert("insert into sys_user(username, password, phone, nickname, role) values(#{username}, #{password}, #{phone}, #{nickname}, #{role})")
    @Options(useGeneratedKeys = true, keyProperty = "id") // 自增ID回填
    int insert(SysUser user);

    // 修改用户信息
    @Update("update sys_user set nickname = #{nickname}, phone = #{phone} where id = #{id}")
    int updateInfo(SysUser user);

    // 修改密码
    @Update("update sys_user set password = #{password} where id = #{id}")
    int updatePassword(@Param("id") Long id, @Param("password") String password);
}
  1. Service 层(业务逻辑)

(1)Service 接口(com.example.useradminapi.service.SysUserService

复制代码
import com.example.useradminapi.entity.SysUser;

/**
 * 用户服务接口
 */
public interface SysUserService {
    // 注册
    String register(String username, String password, String phone, String nickname, String code);

    // 登录
    String login(String username, String password);

    // 查询用户信息
    SysUser getUserInfo(Long userId);

    // 修改个人信息
    boolean updateInfo(Long userId, String nickname, String phone);

    // 修改密码
    boolean updatePassword(Long userId, String oldPassword, String newPassword);
}

(2)Service 实现类(com.example.useradminapi.service.impl.SysUserServiceImpl

复制代码
import com.example.useradminapi.entity.SysUser;
import com.example.useradminapi.mapper.SysUserMapper;
import com.example.useradminapi.util.JwtUtil;
import com.example.useradminapi.util.Md5Util;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

/**
 * 用户服务实现类
 */
@Service
public class SysUserServiceImpl implements SysUserService {
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private JwtUtil jwtUtil;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 注册逻辑
    @Override
    public String register(String username, String password, String phone, String nickname, String code) {
        // 1. 校验验证码(Redis中获取)
        String redisCode = stringRedisTemplate.opsForValue().get("code:" + phone);
        if (redisCode == null || !redisCode.equals(code)) {
            return "验证码错误";
        }
        // 2. 校验用户名/手机号是否已存在
        if (sysUserMapper.selectByUsername(username) != null) {
            return "用户名已存在";
        }
        if (sysUserMapper.selectByPhone(phone) != null) {
            return "手机号已存在";
        }
        // 3. 密码加密
        String encryptPwd = Md5Util.encrypt(password);
        // 4. 新增用户
        SysUser user = new SysUser();
        user.setUsername(username);
        user.setPassword(encryptPwd);
        user.setPhone(phone);
        user.setNickname(nickname);
        user.setRole("USER"); // 默认普通用户
        sysUserMapper.insert(user);
        // 5. 删除Redis中的验证码
        stringRedisTemplate.delete("code:" + phone);
        return "注册成功";
    }

    // 登录逻辑
    @Override
    public String login(String username, String password) {
        // 1. 查询用户
        SysUser user = sysUserMapper.selectByUsername(username);
        if (user == null) {
            return "用户不存在";
        }
        // 2. 校验密码
        String encryptPwd = Md5Util.encrypt(password);
        if (!encryptPwd.equals(user.getPassword())) {
            return "密码错误";
        }
        // 3. 生成JWT令牌
        return jwtUtil.generateToken(user.getId(), user.getUsername(), user.getRole());
    }

    // 查询用户信息
    @Override
    public SysUser getUserInfo(Long userId) {
        SysUser user = sysUserMapper.selectByUsername(null); // 先占位,实际通过ID查(补充Mapper后修改)
        // 补充:实际需新增selectById方法,这里简化,先返回模拟数据
        return user;
    }

    // 修改个人信息
    @Override
    public boolean updateInfo(Long userId, String nickname, String phone) {
        SysUser user = new SysUser();
        user.setId(userId);
        user.setNickname(nickname);
        user.setPhone(phone);
        return sysUserMapper.updateInfo(user) > 0;
    }

    // 修改密码
    @Override
    public boolean updatePassword(Long userId, String oldPassword, String newPassword) {
        // 1. 查询用户
        SysUser user = sysUserMapper.selectByUsername(null); // 需补充selectById
        if (user == null) {
            return false;
        }
        // 2. 校验旧密码
        String encryptOldPwd = Md5Util.encrypt(oldPassword);
        if (!encryptOldPwd.equals(user.getPassword())) {
            return false;
        }
        // 3. 加密新密码并修改
        String encryptNewPwd = Md5Util.encrypt(newPassword);
        return sysUserMapper.updatePassword(userId, encryptNewPwd) > 0;
    }
}
  1. Controller 层(接口暴露)

(1)验证码接口(com.example.useradminapi.controller.CodeController

复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 验证码接口(注册用)
 */
@RestController
@RequestMapping("/code")
public class CodeController {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 获取验证码:/code/send/13800138000
    @GetMapping("/send/{phone}")
    public String sendCode(@PathVariable String phone) {
        // 1. 生成6位随机验证码
        String code = String.valueOf(new Random().nextInt(899999) + 100000);
        // 2. 存入Redis,5分钟过期(接单时可对接短信平台,这里模拟)
        stringRedisTemplate.opsForValue().set("code:" + phone, code, 5, TimeUnit.MINUTES);
        // 3. 返回提示(实际项目中发送短信)
        return "验证码已发送:" + code; // 测试用,正式环境删除code显示
    }
}

(2)用户接口(com.example.useradminapi.controller.SysUserController

复制代码
import com.example.useradminapi.entity.SysUser;
import com.example.useradminapi.service.SysUserService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;

/**
 * 用户接口(注册、登录、信息管理)
 */
@RestController
@RequestMapping("/user")
public class SysUserController {
    @Resource
    private SysUserService sysUserService;

    // 注册接口
    @PostMapping("/register")
    public String register(
            @RequestParam String username,
            @RequestParam String password,
            @RequestParam String phone,
            @RequestParam String nickname,
            @RequestParam String code
    ) {
        return sysUserService.register(username, password, phone, nickname, code);
    }

    // 登录接口
    @PostMapping("/login")
    public String login(
            @RequestParam String username,
            @RequestParam String password
    ) {
        return sysUserService.login(username, password);
    }

    // 查询用户信息
    @GetMapping("/info/{userId}")
    public SysUser getUserInfo(@PathVariable Long userId) {
        return sysUserService.getUserInfo(userId);
    }

    // 修改个人信息
    @PutMapping("/info")
    public boolean updateInfo(
            @RequestParam Long userId,
            @RequestParam String nickname,
            @RequestParam String phone
    ) {
        return sysUserService.updateInfo(userId, nickname, phone);
    }

    // 修改密码
    @PutMapping("/password")
    public boolean updatePassword(
            @RequestParam Long userId,
            @RequestParam String oldPassword,
            @RequestParam String newPassword
    ) {
        return sysUserService.updatePassword(userId, oldPassword, newPassword);
    }
}

四、接口测试(Postman 实操)

  1. 获取验证码

• 请求方式:GET

• 请求地址:http://localhost:8080/code/send/13800138000

• 返回结果:验证码已发送:123456

  1. 用户注册

• 请求方式:POST

• 请求地址:http://localhost:8080/user/register

复制代码
username: testuser
password: 123456
phone: 13800138000
nickname: 测试用户
code: 123456

.返回结果:注册成功

  1. 用户登录

• 请求方式:POST

• 请求地址:http://localhost:8080/user/login

• 参数:

复制代码
username: testuser
password: 123456

返回结果:JWT 令牌字符串(后续接口携带令牌访问)


五、接单交付技巧

1. 代码交付 :将项目打包成 ZIP,包含源代码、SQL 文件、接口文档(用 Swagger 生成);
2. 部署说明 :写一份简易部署文档,包含 "打包命令、服务器启动命令、接口列表";
3. 售后约定 :明确 7 天免费修复 Bug,新增功能按模块收费(比如新增 "用户禁用" 功能收 500 元);
4. 作品集包装:把这个项目的核心接口、测试截图放到 CSDN 博客 / 掘金,标注 "可定制开发",吸引客户。

本章小结

  1. 通用用户管理后端 是接单 "刚需款 ",可直接复用 80% 的代码到不同项目中;

  2. 核心逻辑要做好 "密码加密、验证码校验、JWT 权限",避免客户后期反馈安全问题;

  3. 交付时重点做好 "文档 + 售后约定",提升客户满意度,方便后续复购 / 转介绍。


下一章,我会带大家做第二个实战项目 ------ 小程序订单后端,聚焦接单中高频的 "订单创建、支付回调、查询" 功能,做完就能对接小程序类接单需求!

相关推荐
v***59833 小时前
springBoot连接远程Redis连接失败(已解决)
spring boot·redis·后端
Coder_Boy_5 小时前
基于SpringAI的在线考试系统-企业级软件研发工程应用规范实现细节
大数据·开发语言·人工智能·spring boot
5***b975 小时前
Spring Boot--@PathVariable、@RequestParam、@RequestBody
java·spring boot·后端
qq_318121595 小时前
Java大厂面试故事:Spring Boot、微服务与AI场景深度解析
java·spring boot·redis·微服务·ai·kafka·spring security
L***d6706 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
袁慎建6 小时前
如何发布自定义 Spring Boot Starter
spring boot
BD_Marathon6 小时前
搭建MyBatis框架之优化功能(七)
mybatis
haokan_Jia6 小时前
【一、地质灾害气象风险预警互联系统-自由编辑预警区域,打包生成预警成果】
spring boot
计算机毕设指导67 小时前
基于微信小程序的丽江市旅游分享系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·旅游