一.前言
项目在线预览地址:点击访问,如有问题,可私聊作者
作者一直都有打算想做一个通用的商品、商城类后台管理系统,这样的好处就是以后需要实现什么系统网站等,可充分复用系统和其逻辑,即使有改动也是在小范围,符合良好的开发思维。
主要的想法就是设计好模块管理功能,数据结构设计符合平常化,主要有几点:
- 功能设计,商品、商城类一般都包含这几大模块:首页轮播图、商品分类、推荐分类、商品管理、订单管理、评论管理、管理员管理等;
- 配置类设计,配置的东西一般要求可复用,避免重复不必要的开发,并且简单易用,例如一些字典、参数的配置;
- 数据库表结构、字段属性设计合理
- 接口访问参数等设计合理
以上是作者的一些观点或想法,说起来容易,做起来其实也不难(哈哈哈~)
二.项目效果图
登录,还是最平常的登录,jwt token登录
swagger开发文档
欢迎页
个人中心,信息、密码修改等
管理员管理
商品分类,树形列表,一对多层级关系
首页轮播图
推荐分类,一对多关系,绑定商品分类(不能父级分类)
商品管理,最多上传9张图片,商品详情支持富文本录入,图片等,所属商品分类支持多选,一对多关系
配置类相关
字典配置,一些日常生活中规范的描述可利用字典来配置实现,也是等价于代码里面的枚举,通过唯一编码code来确定
参数配置,与字典类似,通过唯一编码code来确定,支持富文本录入
三.正式入手实现,数据表设计
这里看表设计,表之间的联系,自然就明白了其中只逻辑,很关键的也是很重要的作为程序员的一个基础,以下是作者目前设计所涉及的数据表:
-- 系统管理员
CREATE TABLE `admin` (
`id` bigint NOT NULL COMMENT '主键',
`username` varchar(60) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '登录密码',
`real_name` varchar(32) DEFAULT NULL COMMENT '姓名',
`gender` tinyint(1) DEFAULT 0 COMMENT '用户性别 0保密 1男 2女',
`avatar` varchar(300) DEFAULT NULL COMMENT '头像',
`phone` varchar(20) DEFAULT NULL COMMENT '手机',
`email` varchar(60) DEFAULT NULL COMMENT '邮箱',
`remark` varchar(200) DEFAULT NULL COMMENT '备注',
`status` tinyint(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
`admin_type` tinyint(1) DEFAULT '1' COMMENT '管理员类型 0超级管理员 1普通管理员',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `admin_key_username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理员';
-- 商品分类
CREATE TABLE `product_type` (
`id` bigint NOT NULL COMMENT '主键',
`parent_id` bigint NOT NULL DEFAULT 0 COMMENT '父主键',
`type_name` varchar(255) NOT NULL COMMENT '分类名称',
`sort` int NOT NULL DEFAULT 0 COMMENT '排序,越小越靠前',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`status` tinyint(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品分类';
-- 首页推荐分类
CREATE TABLE `recommend_type` (
`id` bigint NOT NULL COMMENT '主键',
`name` varchar(255) NOT NULL COMMENT '分类名称',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`sort` int NOT NULL DEFAULT 0 COMMENT '排序,越小越靠前',
`status` tinyint(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='首页推荐分类';
-- 首页推荐分类行项目
CREATE TABLE `recommend_type_item` (
`id` bigint NOT NULL COMMENT '主键',
`parent_id` bigint NOT NULL DEFAULT 0 COMMENT '父级主键',
`product_type_id` bigint NOT NULL DEFAULT 0 COMMENT '商品分类主键',
`status` tinyint(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='首页推荐分类行项目';
-- 商品
CREATE TABLE `product`
(
`id` bigint NOT NULL COMMENT '主键',
`product_name` varchar(225) NOT NULL COMMENT '商品名称',
`product_des` varchar(225) DEFAULT NULL COMMENT '商品描述',
`price` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '商品单价',
`original_price` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '商品原价',
`material` varchar(225) DEFAULT NULL COMMENT '材料',
`pack` varchar(225) DEFAULT NULL COMMENT '包装',
`send_word` varchar(225) DEFAULT NULL COMMENT '寄语',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`cover_path` varchar(500) DEFAULT NULL COMMENT '商品封面图片',
`img_path` varchar(2000) DEFAULT NULL COMMENT '商品图片,多张英文逗号分割',
`content` longtext DEFAULT NULL COMMENT '商品详情内容',
`sort` int NOT NULL DEFAULT 0 COMMENT '排序,越小越靠前',
`stock` int NOT NULL DEFAULT 0 COMMENT '商品库存',
`sale_num` int NOT NULL DEFAULT 0 COMMENT '商品销量',
`version` int NOT NULL DEFAULT 0 COMMENT '版本号',
`status` tinyint(1) DEFAULT 1 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='商品';
-- 商品所属分类
CREATE TABLE `product_type_item` (
`id` bigint NOT NULL COMMENT '主键',
`product_id` bigint NOT NULL DEFAULT 0 COMMENT '商品主键',
`product_type_id` bigint NOT NULL DEFAULT 0 COMMENT '商品分类主键',
`status` tinyint(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='首页推荐分类行项目';
-- 系统字典
CREATE TABLE `system_dict` (
`id` bigint NOT NULL COMMENT '主键',
`parent_id` bigint NOT NULL DEFAULT '0' COMMENT '父主键',
`code` varchar(255) NOT NULL COMMENT '字典编码',
`dict_key` int DEFAULT NULL COMMENT '字典值',
`dict_name` varchar(255) NOT NULL COMMENT '字典名称',
`sort` int NOT NULL DEFAULT 0 COMMENT '排序,越小越靠前',
`remark` varchar(255) DEFAULT NULL COMMENT '字典备注',
`status` tinyint(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统字典';
-- 系统参数
CREATE TABLE `system_param` (
`id` bigint NOT NULL COMMENT '主键',
`code` varchar(255) NOT NULL COMMENT '参数编码,唯一',
`title` varchar(255) NOT NULL COMMENT '标题',
`content` longtext NOT NULL COMMENT '内容',
`sort` int NOT NULL DEFAULT 0 COMMENT '排序,越小越靠前',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`status` tinyint(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统参数';
-- 2022-10-19 用户信息
CREATE TABLE `user_info`
(
`id` bigint NOT NULL COMMENT '主键',
`nickname` varchar(10) NOT NULL COMMENT '用户名称',
`phone` varchar(20) NOT NULL COMMENT '手机号',
`password` varchar(255) NOT NULL COMMENT '登录密码 加密',
`avatar` varchar(225) DEFAULT NULL COMMENT '头像',
`gender` TINYINT(1) DEFAULT 0 COMMENT '性别 0保密 1男 2女',
`signature` varchar(225) DEFAULT NULL COMMENT '个性签名',
`remark` varchar(225) DEFAULT NULL COMMENT '备注',
`status` TINYINT(1) DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_time` datetime(0) COMMENT '创建时间',
`update_time` datetime(0) COMMENT '更新时间',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间-管理员',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID-管理员',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `phone` (`phone`) USING BTREE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='用户信息';
-- 首页轮播图
CREATE TABLE `banner`
(
`id` bigint NOT NULL COMMENT '主键',
`img_path` varchar(500) DEFAULT NULL COMMENT '图片路径',
`route_path` varchar(255) DEFAULT NULL COMMENT '路由路径',
`route_param` varchar(255) DEFAULT NULL COMMENT '路由参数(json格式)',
`sort` INT(11) NOT NULL DEFAULT 0 COMMENT '排序,越小越靠前',
`remark` varchar(225) DEFAULT NULL COMMENT '备注',
`status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_system_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_system_admin_id` bigint DEFAULT NULL COMMENT '创建人ID',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='首页轮播图';
-- 订单
CREATE TABLE `product_order` (
`id` bigint NOT NULL COMMENT '主键',
`order_num` varchar(100) DEFAULT NULL COMMENT '订单号',
`user_id` bigint NOT NULL COMMENT '所属用户',
`pay_amount` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '支付金额',
`send_time` datetime DEFAULT NULL COMMENT '送货日期',
`send_type` tinyint(1) DEFAULT 1 COMMENT '送货时间类型(系统字典)',
`receiver_name` varchar(225) NOT NULL COMMENT '收货人姓名',
`receiver_phone` varchar(225) NOT NULL COMMENT '收货人联系电话',
`receiver_addr` varchar(225) NOT NULL COMMENT '收货人地址',
`receiver_remark` varchar(225) DEFAULT NULL COMMENT '收货人备注',
`pay_status` tinyint(1) DEFAULT 1 COMMENT '支付状态 1待支付 2已支付 3支付失败 4已取消',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间-管理员',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID-管理员',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `order_num` (`order_num`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单';
-- 订单行项目
CREATE TABLE `product_order_item` (
`id` bigint NOT NULL COMMENT '主键',
`parent_id` bigint NOT NULL DEFAULT 0 COMMENT '订单主键',
`order_num` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '订单号',
`product_id` bigint NOT NULL COMMENT '商品主键',
`product_name` varchar(225) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称',
`product_des` varchar(225) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '商品描述',
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品单价',
`original_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品原价',
`cover_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '商品封面图片',
`product_num` int DEFAULT '0' COMMENT '商品购买数量',
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='订单行项目';
-- 商品评论
CREATE TABLE `product_comment`
(
`id` bigint NOT NULL COMMENT '主键',
`user_id` bigint NOT NULL COMMENT '用户主键',
`product_id` bigint NOT NULL COMMENT '商品主键',
`order_id` bigint NOT NULL COMMENT '订单主键',
`order_item_id` bigint NOT NULL COMMENT '订单行项目主键',
`content` varchar(1000) DEFAULT NULL COMMENT '评论内容',
`img_path` varchar(2000) DEFAULT NULL COMMENT '商品图片,多张英文逗号分割',
`status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否禁用 0否 1是',
`deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记 是否已删除: 0否 1是',
`create_time` datetime(0) COMMENT '创建时间',
`update_time` datetime(0) COMMENT '更新时间',
`update_system_time` datetime DEFAULT NULL COMMENT '更新时间-管理员',
`update_system_admin_id` bigint DEFAULT NULL COMMENT '修改人ID-管理员',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='商品评论';
四.源码实现
项目结构截图,idea开发工具
AdminController:
package com.product.controller;
import com.product.entity.base.Result;
import com.product.entity.base.ResultPage;
import com.product.entity.req.AdminPageReq;
import com.product.entity.vo.AdminVO;
import com.product.service.AdminService;
import com.product.util.CommonUtil;
import com.product.util.JwtUtil;
import com.product.util.RedisUtil;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
/**
* @author hjf
* @date 2022-10-19 10:26
* @describe 管理员controller
*/
@Api(tags = "管理员")
@Slf4j
@RestController
@RequestMapping("/system/admin")
public class AdminController {
@Resource
private AdminService adminService;
@ApiOperation(value = "账密登录", notes = "账密登录")
@GetMapping("/login")
public Result<AdminVO> login(
@ApiParam("电话") @RequestParam("username") String username,
@ApiParam("密码") @RequestParam("password") String password,
HttpServletRequest request, HttpServletResponse response
) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
//清除认证
new SecurityContextLogoutHandler().logout(request, response, authentication);
}
return adminService.login(username,password);
}
@ApiOperation(value = "用户退出登录", notes = "用户退出登录")
@GetMapping("/logout")
public Result<?> logout(HttpServletRequest request, HttpServletResponse response) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
//清除认证
new SecurityContextLogoutHandler().logout(request, response, authentication);
}
RedisUtil.logout(JwtUtil.getUserId());
return Result.OK();
}
@PostMapping("/add")
@ApiOperation(value = "添加", notes = "添加")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "ID", required = false, dataType = "Long", paramType = "query"),
@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "password", value = "密码", required = false, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "confirmPassword", value = "确认密码", required = false, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "realName", value = "姓名", required = false, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "gender", value = "性别", required = true, dataType = "Integer", paramType = "query"),
@ApiImplicitParam(name = "phone", value = "手机", required = true, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "email", value = "邮箱", required = false, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "remark", value = "备注", required = false, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "file", value = "头像文件", required = false, dataType = "MultipartFile", paramType = "query")
})
public Result<AdminVO> add(
@RequestParam(value = "id",required = false) Long id,
@RequestParam("username") String username,
@RequestParam(value = "password",required = false) String password,
@RequestParam(value = "confirmPassword",required = false) String confirmPassword,
@RequestParam(value = "realName",required = false) String realName,
@RequestParam("gender") Integer gender,
@RequestParam("phone") String phone,
@RequestParam(value = "email",required = false) String email,
@RequestParam(value = "remark",required = false) String remark,
@RequestParam(value = "file",required = false) MultipartFile file
) {
AdminVO adminVO = new AdminVO();
adminVO.setId(id);
adminVO.setUsername(username);
adminVO.setPassword(password);
adminVO.setConfirmPassword(confirmPassword);
adminVO.setRealName(realName);
adminVO.setGender(gender);
adminVO.setPhone(phone);
adminVO.setEmail(email);
adminVO.setRemark(remark);
adminVO.setFile(file);
return adminService.add(JwtUtil.getUserId(),adminVO);
}
@ApiOperation("分页")
@PostMapping("/getPage")
public ResultPage<AdminVO> getPage(@RequestBody AdminPageReq adminPageReq) {
return adminService.getPage(JwtUtil.getUserId(),adminPageReq);
}
@ApiOperation("详情")
@GetMapping("/getDetail")
public Result<AdminVO> getDetail(@RequestParam("id") Long id) {
return Result.OK(adminService.getVOById(id));
}
@ApiOperation("更新状态")
@PostMapping("/updateStatus")
public Result<?> updateStatus(@RequestParam("ids") String ids, @RequestParam("status") Integer status) {
List<Long> idList = CommonUtil.stringToLongList(ids);
return adminService.updateStatus(JwtUtil.getUserId(),idList,status);
}
@ApiOperation("删除")
@PostMapping("/del")
public Result<?> del(@RequestParam("ids") String ids) {
List<Long> idList = CommonUtil.stringToLongList(ids);
return adminService.del(JwtUtil.getUserId(),idList);
}
@ApiOperation("修改密码")
@PostMapping("/updatePassword")
public Result<?> updatePassword(
@RequestParam("id") Long id,
@RequestParam("password") String password,
@RequestParam("confirmPassword") String confirmPassword) {
return adminService.updatePassword(JwtUtil.getUserId(),id,password,confirmPassword);
}
}
AdminService:
package com.product.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.product.entity.Admin;
import com.product.entity.base.Result;
import com.product.entity.base.ResultPage;
import com.product.entity.req.AdminPageReq;
import com.product.entity.vo.AdminVO;
import java.util.List;
/**
* @author hjf
* @date 2022-10-19 10:26
* @describe 用户service
*/
public interface AdminService extends IService<Admin> {
Result<AdminVO> login(String username, String password);
AdminVO getByUsername(String username);
AdminVO getVOById(Long id);
Result<AdminVO> add(Long userId,AdminVO adminVO);
ResultPage<AdminVO> getPage(Long userId, AdminPageReq adminPageReq);
Result<?> updateStatus(Long userId, List<Long> ids, Integer status);
Result<?> del(Long userId,List<Long> ids);
Result<?> updatePassword(Long userId,Long id,String password,String confirmPassword);
}
AdminServiceImpl:
package com.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.product.config.fileupload.FileUploadConfig;
import com.product.config.security.TokenConfig;
import com.product.entity.Admin;
import com.product.entity.base.Result;
import com.product.entity.base.ResultPage;
import com.product.entity.req.AdminPageReq;
import com.product.entity.vo.AdminVO;
import com.product.enumerate.Gender;
import com.product.enumerate.YesOrNo;
import com.product.mapper.AdminMapper;
import com.product.service.AdminService;
import com.product.service.FileUploadService;
import com.product.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author hjf
* @date 2022-10-19 10:26
* @describe 管理员service
*/
@Slf4j
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {
@Value("${server.port}")
private String port;
@Resource
private RestTemplate restTemplate;
@Resource
private TokenConfig tokenConfig;
@Resource
private FileUploadConfig fileUploadConfig;
@Resource
private FileUploadService fileUploadService;
/**
* 管理员登录
*
*/
@Override
public Result<AdminVO> login(String username, String password){
AdminVO adminVO = getByUsername(username);
if(adminVO != null){
if(adminVO.getDeleted().equals(YesOrNo.YES.getValue())){
return Result.failMsg("登录失败,账号已注销");
}
if(adminVO.getStatus().equals(YesOrNo.YES.getValue())){
return Result.failMsg("登录失败,账号已禁用,请联系客服人员");
}
PasswordEncoder encoder = new BCryptPasswordEncoder();
boolean matches = encoder.matches(password, adminVO.getPassword());
if (!matches) {
return Result.failMsg("账号或密码错误");
}
//缓存登录密码
RedisUtil.setLoginPassword(username + "_admin",password);
//一定要在获取token前缓存redis,否则可能报错
RedisUtil.setAdmin(adminVO);
String accessToken = getOAuthToken(adminVO,password);
if(accessToken == null){
return Result.failMsg("登录失败,请重试");
}
adminVO.setAccessToken(accessToken);
return Result.OK(adminVO);
}else{
return Result.failMsg("账号或密码错误");
}
}
@Override
public AdminVO getByUsername(String username){
AdminVO adminVO = null;
LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Admin::getUsername,username).last("LIMIT 1");
Admin admin = getOne(queryWrapper);
if(admin != null){
adminVO = new AdminVO();
BeanUtil.copyProperties(admin,adminVO);
Gender gender = Gender.valueOf(adminVO.getGender());
adminVO.setGenderText(gender.getText());
adminVO.setAvatar(fileUploadService.getImgPath(adminVO.getAvatar()));
}
return adminVO;
}
/**
* 获取用户详情
*/
@Override
public AdminVO getVOById(Long id) {
AdminVO adminVO = null;
//方式1
Admin admin = getById(id);
if(admin != null){
adminVO = new AdminVO();
BeanUtil.copyProperties(admin,adminVO);
Gender gender = Gender.valueOf(adminVO.getGender());
adminVO.setGenderText(gender.getText());
adminVO.setAvatar(fileUploadService.getImgPath(adminVO.getAvatar()));
}
return adminVO;
}
/**
* 调用OAuth2的获取令牌接口
*
* @description 1.将用户信息存入公共map中 2.获取访问令牌 3.写入"刷新令牌"到数据库
*
*/
private String getOAuthToken(AdminVO adminVO,String password) {
//获取OAuth2框架的配置信息,用于访问刷新令牌接口
Map<String, String> tokenMap = tokenConfig.getConfig();
Map<String,String> mapParam = new HashMap<>();
mapParam.put("username", adminVO.getUsername() + "_admin");
mapParam.put("password", password);
mapParam.put("client_id", tokenMap.get("clientId"));
mapParam.put("client_secret", tokenMap.get("secret"));
mapParam.put("grant_type", tokenMap.get("grantTypes"));
try {
@SuppressWarnings("unchecked")
Map<String, String> mapResult = restTemplate
.getForObject(
"http://localhost:"+port+"/oauth/token?username={username}&password={password}&client_id={client_id}&client_secret={client_secret}&grant_type={grant_type}",
Map.class, mapParam);
if(mapResult != null){
try {
RedisUtil.setRefreshToken(adminVO.getId(),mapResult.get("refresh_token"));
} catch (Exception e) {
e.printStackTrace();
}
return mapResult.get("access_token");
}
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 新增
*
*/
@Override
public Result<AdminVO> add(Long userId,AdminVO adminVO){
if(adminVO.getId() == null && (adminVO.getPassword() == null || adminVO.getConfirmPassword() == null)){
return Result.failMsg("请输入密码");
}
if(adminVO.getId() == null && !Objects.equals(adminVO.getPassword(),adminVO.getConfirmPassword())){
return Result.failMsg("两次输入密码不一致,请重新输入");
}
if(adminVO.getId() == null && adminVO.getFile() == null){
return Result.failMsg("请上传头像");
}
AdminVO old = getByUsername(adminVO.getUsername());
if(old != null && !Objects.equals(old.getId(),adminVO.getId())){
return Result.failMsg("用户名已存在,请修改");
}
if(adminVO.getFile() != null){
String avatar = fileUploadService.uploadImage(adminVO.getFile());
adminVO.setAvatar(avatar);
}
Admin admin = null;
if(adminVO.getId() != null){
admin = getById(adminVO.getId());
if(admin == null){
return Result.failMsg("管理员不存在");
}
}
LocalDateTime now = LocalDateTime.now();
if(admin == null){
admin = new Admin();
admin.setId(IdWorker.getId());
admin.setCreateSystemTime(now);
admin.setCreateSystemAdminId(userId);
adminVO.setPassword(new BCryptPasswordEncoder().encode(adminVO.getPassword()));
adminVO.setStatus(YesOrNo.NO.getValue());
adminVO.setDeleted(YesOrNo.NO.getValue());
}
adminVO.setUpdateSystemTime(now);
adminVO.setUpdateSystemAdminId(userId);
BeanUtil.copyProperties(adminVO, admin, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
saveOrUpdate(admin);
adminVO.setFile(null);
BeanUtil.copyProperties(admin, adminVO, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
adminVO.setAvatar(fileUploadService.getImgPath(adminVO.getAvatar()));
return Result.OK("保存成功",adminVO);
}
/**
* 分页
*/
@Override
public ResultPage<AdminVO> getPage(Long userId, AdminPageReq adminPageReq) {
LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(adminPageReq.getUsername()!=null,Admin::getUsername, adminPageReq.getUsername());
queryWrapper.eq(adminPageReq.getStatus()!=null, Admin::getStatus, adminPageReq.getStatus());
queryWrapper.orderByDesc(Admin::getCreateSystemTime);
Page<Admin> page = page(adminPageReq.build(), queryWrapper);
List<AdminVO> list = new ArrayList<>();
if (page.getTotal() > 0) {
list = page.getRecords().stream().map(admin -> {
AdminVO adminVO = BeanUtil.copyProperties(admin, AdminVO.class);
Gender gender = Gender.valueOf(adminVO.getGender());
adminVO.setGenderText(gender.getText());
adminVO.setAvatar(fileUploadService.getImgPath(adminVO.getAvatar()));
return adminVO;
}).collect(Collectors.toList());
}
return ResultPage.OK(page.getTotal(), page.getCurrent(), page.getSize(), list);
}
@Override
public Result<?> updateStatus(Long userId,List<Long> ids,Integer status){
YesOrNo yesOrNo = YesOrNo.valueOf(status);
if(yesOrNo == null){
return Result.failMsg("状态非法");
}
String msg = "启用成功";
if(Objects.equals(yesOrNo,YesOrNo.YES)){
msg = "禁用成功";
}
List<Admin> admins = new ArrayList<>();
LocalDateTime now = LocalDateTime.now();
for(Long id : ids){
Admin admin = new Admin();
admin.setId(id);
admin.setStatus(yesOrNo.getValue());
admin.setUpdateSystemAdminId(userId);
admin.setUpdateSystemTime(now);
admins.add(admin);
}
updateBatchById(admins);
return Result.OKMsg(msg);
}
@Override
public Result<?> del(Long userId,List<Long> ids){
remove(Wrappers.<Admin>lambdaQuery().in(Admin::getId,ids));
// List<Admin> admins = new ArrayList<>();
// LocalDateTime now = LocalDateTime.now();
// for(Long id : ids){
// Admin admin = new Admin();
// admin.setId(id);
// admin.setDeleted(YesOrNo.YES.getValue());
// admin.setUpdateSystemAdminId(userId);
// admin.setUpdateSystemTime(now);
// admins.add(admin);
// }
// updateBatchById(admins);
return Result.OKMsg("删除成功");
}
@Override
public Result<?> updatePassword(Long userId,Long id,String password,String confirmPassword){
if(!Objects.equals(password,confirmPassword)){
return Result.failMsg("两次输入密码不一致,请重新输入");
}
Admin admin = getById(id);
if(admin != null){
admin.setPassword(new BCryptPasswordEncoder().encode(password));
updateById(admin);
return Result.OKMsg("修改成功");
}
return Result.failMsg("修改失败");
}
}
五.总结
暂时订单、评论还未实现,后期继续增加菜单管理,管理员角色、权限管理等,有兴趣的同学可以关注一下,期待作者可以快点实现和完善功能,当然,对应此管理后台的商城网站作者已经有了构思,管理后台实现后,即着手去实现商城网站,让它成为一套完整的系统。
获取源码或有任何问题的朋友可通过博客最后的名片添加作者或留言、私聊都可。
感谢您的阅读~