【SpringBoot3+Vue3】二【实战篇】-后端

目录

一、环境搭建

1、数据库脚本

2、pom

3、yml

4、通过mybatis-X生成实体pojo等

4.1 Article

4.2 Category

4.3 User

5、 Mapper

5.1 ArticleMapper

5.2 CategoryMapper

5.3 UserMapper

6、service

6.1 ArticleService

6.2 CategoryService

6.3 UserService

7、serviceImpl

7.1 ArticleServiceImpl

7.2 CategoryServiceImpl

7.3 UserServiceImpl

8、统一返回类Result

9、工具类

9.1 MD5加密工具类Md5Util

9.2 jwt生成token工具类JwtUtils 

9.3 工具类ThreadLocalUtil

 9.4 AliOSSProperties阿里云参数实体

9.5 阿里云AliOSSUtils

10、全局异常处理类GlobalExceptionHandler

11、拦截器LoginCheckInterceptor

12、配置类

 12.1 配置类WebConfig注册拦截器

12.2   MybatisPlus分页配置类MybatisPlusConfig

13、自定义注解(新增文章)

13.1 新增文章自定义注解State接口

13.2 新增文章自定义注解实现类StateValidation

14、封装分页实体PageBean

二、用户

1、注册

1.1 UserController

1.2 service

1.3 serviceImpl

2、登录

2.1 UserController

2.2 登录认证 

3、获取用户详细信息

3.1 UserController

 3.2 servcie

3.3 servcieImpl

3.4 优化版本UserController(使用ThreadLocal)

4、更新用户基本信息

4.1 UserController

4.2 servcie

4.3 serviceImpl

5、更新用户头像

5.2 UserController 

5.2 servcie

5.3 servcieImpl

6、更新用户密码

6.1 UserController

6.2 service

6.3 serviceImpl

三、文章分类

1、新增文章分类

1.1 CategoryController

1.2 service

1.3 servcieImpl

2、文章分类列表

2.1 CategoryController

2.2 service

2.3 servcieImpl

3、 获取文章分类详情

3.1 CategoryController

3.2 service

3.3 servcieImpl

4、更新文章分类

4.1 CategoryController

4.2 service

4.3 servcieImpl

5、删除文章分类

5.1 CategoryController

5.2 service

5.3 servcieImpl

四、文章管理

1、新增文章

1.1 ArticleCtroller

1.2 service

1.3 serviceImpl

2、文章列表(条件分页)

2.1 ArticleCtroller

2.2 service

2.3 serviceImpl

3、获取文章详情

3.1 ArticleCtroller

3.2 service

3.3 serviceImpl

4、更新文章

4.1 ArticleCtroller

4.2 service

4.3 serviceImpl

5、删除文章

5.1 ArticleCtroller

5.2 service

5.3 serviceImpl

五、上传接口

1、FileUploadController


前言:SpringBoot3+Vue3项目实战-后端

一、环境搭建

1、数据库脚本

-- 用户表
create table user (id int unsigned primary key auto_increment comment 'ID',username varchar(20) not null unique comment '用户名',password varchar(32)  comment '密码',nickname varchar(10)  default '' comment '昵称',email varchar(128) default '' comment '邮箱',user_pic varchar(128) default '' comment '头像',create_time datetime not null comment '创建时间',update_time datetime not null comment '修改时间'
) comment '用户表';-- 分类表
create table category(id int unsigned primary key auto_increment comment 'ID',category_name varchar(32) not null comment '分类名称',category_alias varchar(32) not null comment '分类别名',create_user int unsigned not null comment '创建人ID',create_time datetime not null comment '创建时间',update_time datetime not null comment '修改时间',constraint fk_category_user foreign key (create_user) references user(id) -- 外键约束
);-- 文章表
create table article(id int unsigned primary key auto_increment comment 'ID',title varchar(30) not null comment '文章标题',content varchar(10000) not null comment '文章内容',cover_img varchar(128) not null  comment '文章封面',state varchar(3) default '草稿' comment '文章状态: 只能是[已发布] 或者 [草稿]',category_id int unsigned comment '文章分类ID',create_user int unsigned not null comment '创建人ID',create_time datetime not null comment '创建时间',update_time datetime not null comment '修改时间',constraint fk_article_category foreign key (category_id) references category(id),-- 外键约束constraint fk_article_user foreign key (create_user) references user(id) -- 外键约束
)

2、pom

<?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.1.5</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.bocai</groupId><artifactId>mybatis-plus-module</artifactId><version>0.0.1-SNAPSHOT</version><name>mybatis-plus-module</name><description>mybatis-plus-module</description><properties><java.version>17</java.version><aliyun-sdk-oss.version>3.15.1</aliyun-sdk-oss.version><jaxb-api.version>2.3.1</jaxb-api.version><activation.version>1.1.1</activation.version><jaxb-runtime.version>2.3.3</jaxb-runtime.version><mybatis-plus.version>3.5.3</mybatis-plus.version><druid.version>1.1.23</druid.version><jjwt.version>0.9.0</jjwt.version><fastjson.version>1.2.76</fastjson.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.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--  校验 引入validation --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!--  3、 引入mybatisplus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><!--        阿里云OSS依赖--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>${aliyun-sdk-oss.version}</version></dependency><!--  如果是java9 还需要下面几个依赖   本项目按理不需要--><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>${jaxb-api.version}</version></dependency><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>${activation.version}</version></dependency><!-- no more than 2.3.3--><dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>${jaxb-runtime.version}</version></dependency><!--  上面都是阿里云的 依赖-  --><!--JWT令牌--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>${jjwt.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><image><builder>paketobuildpacks/builder-jammy-base:latest</builder></image><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

3、yml

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springboot_vue?serverTimezone=UTCusername: rootpassword: Miamimain:banner-mode: off  # 关闭控制台springboot的logomybatis-plus:configuration:map-underscore-to-camel-case: true # 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 控制台显示sqldefault-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler  # 配置全局枚举处理器,好像还有说json的global-config:db-config:id-type: auto   # 数据库id生产规则全局 配置 # ASSIGN_ID雪花算法,数据库id建议使用Long类型logic-delete-field: deleted # 全局配置逻辑删除字段名logic-delete-value: 0 # 全局配置# 逻辑已删除值(默认为 1)这里因为我是反的所以改成0logic-not-delete-value: 1  # 逻辑未删除值(默认为 0)这里因为我是反的所以改成1# table-prefix: tbl_    # 数据库表前缀全局配置banner: false   # 关闭控制台mybatis-plus的logo
#  type-enums-package: com.bocai.enums   # 扫描通用枚举包 或者使用上面那个枚举全局配置# 阿里云OSS配置
aliyun:oss:endpoint: https://oss-cn-hanzhou.aliyuncs.comaccessKeyId: LTjfk332422slksPqyaccessKeySecret: Pfslfksd2;lf2sALHfdsfsTHm6fdsfsdsRbucketName: web-spring3bocai

4、通过mybatis-X生成实体pojo等

4.1 Article

package com.bocai.pojo;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 java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;import com.bocai.anno.State;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.groups.Default;
import lombok.Data;
import org.hibernate.validator.constraints.URL;/*** * @TableName article*/
@TableName(value ="article")
@Data
public class Article implements Serializable {/*** ID*/@NotNull(groups = Article.Update.class)@TableId(type = IdType.AUTO)private Integer id;/*** 文章标题*/@NotEmpty@Pattern(regexp = "^\\S{1,10}$")private String title;/*** 文章内容*/@NotEmptyprivate String content;/*** 文章封面*/@NotEmpty@URLprivate String coverImg;/*** 文章状态: 只能是[已发布] 或者 [草稿]*/@State  //自定义注解private String state;/*** 文章分类ID*/@NotNullprivate Integer categoryId;/*** 创建人ID*/@JsonIgnore  // json返回不显示private Integer createUser;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;/*** 修改时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime updateTime;@TableField(exist = false)private static final long serialVersionUID = 1L;// 如果说某个校验项没有指定分钟,默认属于Default分组//分组之间可以继承,A extend B, 那么A 就拥有B的所有校验项/*** 为了校验分组*/public interface Add extends Default {}/*** 为了校验分组*/public interface Update extends Default{}
}

4.2 Category

package com.bocai.pojo;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 java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.groups.Default;
import lombok.Data;/*** * @TableName category*/
@TableName(value ="category")
@Data
public class Category implements Serializable {/*** ID*/@NotNull(groups = Update.class)@TableId(type = IdType.AUTO)private Integer id;/*** 分类名称*/@NotEmpty  //值不能为空,并且内容不能为空private String categoryName;/*** 分类别名*/@NotEmpty //值不能为空,并且内容不能为空
//    @NotEmpty(groups = {Update.class,Add.class})private String categoryAlias;/*** 创建人ID*/@JsonIgnore  // json返回不显示private Integer createUser;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;/*** 修改时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime updateTime;@TableField(exist = false)private static final long serialVersionUID = 1L;// 如果说某个校验项没有指定分钟,默认属于Default分组//分组之间可以继承,A extend B, 那么A 就拥有B的所有校验项/*** 为了校验分组*/public interface Add extends Default {}/*** 为了校验分组*/public interface Update extends Default{}
}

4.3 User

package com.bocai.pojo;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 java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;/*** 用户表* @TableName user*/
@TableName(value ="user")
@Data
public class User implements Serializable {/*** ID*/@NotNull //不能为空@TableId(type = IdType.AUTO)private Integer id;/*** 用户名*/private String username;/*** 密码*/@JsonIgnore //springboot把当前对象转换成json字符串的时候忽略这个字段private String password;/*** 昵称*/@NotEmpty  //值不能为空,并且内容不能为空@Pattern(regexp = "^\\S{1,10}$")  //正则private String nickname;/*** 邮箱*/@Email //满足邮箱格式private String email;/*** 头像*/private String userPic;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;/*** 修改时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime updateTime;@TableField(exist = false)private static final long serialVersionUID = 1L;
}

5、 Mapper

5.1 ArticleMapper

package com.bocai.mapper;import com.bocai.pojo.Article;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;/**
* @author cheng
* @description 针对表【article】的数据库操作Mapper
* @createDate 2023-11-13 19:55:11
* @Entity com.bocai.pojo.Article
*/
@Mapper
public interface ArticleMapper extends BaseMapper<Article> {}

5.2 CategoryMapper

package com.bocai.mapper;import com.bocai.pojo.Category;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;/**
* @author cheng
* @description 针对表【category】的数据库操作Mapper
* @createDate 2023-11-13 19:55:04
* @Entity com.bocai.pojo.Category
*/
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {}

5.3 UserMapper

package com.bocai.mapper;import com.bocai.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Mapper
* @createDate 2023-11-13 19:54:41
* @Entity com.bocai.pojo.User
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {}

6、service

6.1 ArticleService

package com.bocai.service;import com.bocai.pojo.Article;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【article】的数据库操作Service
* @createDate 2023-11-13 19:55:11
*/
public interface ArticleService extends IService<Article> {}

6.2 CategoryService

package com.bocai.service;import com.bocai.pojo.Category;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【category】的数据库操作Service
* @createDate 2023-11-13 19:55:04
*/
public interface CategoryService extends IService<Category> {}

6.3 UserService

package com.bocai.service;import com.bocai.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service
* @createDate 2023-11-13 19:54:41
*/
public interface UserService extends IService<User> {}

7、serviceImpl

7.1 ArticleServiceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Article;
import com.bocai.service.ArticleService;
import com.bocai.mapper.ArticleMapper;
import org.springframework.stereotype.Service;/**
* @author cheng
* @description 针对表【article】的数据库操作Service实现
* @createDate 2023-11-13 19:55:11
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>implements ArticleService{}

7.2 CategoryServiceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Category;
import com.bocai.service.CategoryService;
import com.bocai.mapper.CategoryMapper;
import org.springframework.stereotype.Service;/**
* @author cheng
* @description 针对表【category】的数据库操作Service实现
* @createDate 2023-11-13 19:55:04
*/
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>implements CategoryService{}

7.3 UserServiceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.mapper.UserMapper;
import org.springframework.stereotype.Service;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2023-11-13 19:54:41
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{}

8、统一返回类Result

package com.bocai.common;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {private Integer code;//响应码,1 代表成功; 0 代表失败private String msg;  //响应信息 描述字符串private Object data; //返回的数据//增删改 成功响应public static Result success(){return new Result(1,"success",null);}//查询 成功响应public static Result success(Object data){return new Result(1,"success",data);}//失败响应public static Result error(String msg){return new Result(0,msg,null);}
}

9、工具类

9.1 MD5加密工具类Md5Util

package com.bocai.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);}}

9.2 jwt生成token工具类JwtUtils 

package com.bocai.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;
import java.util.Map;public class JwtUtils {private static String signKey = "bocai";private static Long expire = 43200000L;  // 12h/*** 生成JWT令牌* @param claims JWT第二部分负载 payload 中存储的内容* @return*/public static String generateJwt(Map<String, Object> claims){String jwt = Jwts.builder().addClaims(claims).signWith(SignatureAlgorithm.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact();return jwt;}/*** 解析JWT令牌* @param jwt JWT令牌* @return JWT第二部分负载 payload 中存储的内容*/public static Claims parseJWT(String jwt){Claims claims = Jwts.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();return claims;}
}

9.3 工具类ThreadLocalUtil

package com.bocai.utils;import java.util.HashMap;
import java.util.Map;/*** ThreadLocal 工具类*/
@SuppressWarnings("all")
public class ThreadLocalUtil {//提供ThreadLocal对象,private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();//根据键获取值public static <T> T get(){return (T) THREAD_LOCAL.get();}//存储键值对public static void set(Object value){THREAD_LOCAL.set(value);}//清除ThreadLocal 防止内存泄漏public static void remove(){THREAD_LOCAL.remove();}
}

 9.4 AliOSSProperties阿里云参数实体

package com.bocai.utils;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;
}

9.5 阿里云AliOSSUtils

package com.bocai.utils;import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;/*** 阿里云 OSS 工具类*/
@Component
public class AliOSSUtils {//    @Value("${aliyun.oss.endpoint}")
//    private String endpoint;
//    @Value("${aliyun.oss.accessKeyId}")
//    private String accessKeyId;
//    @Value("${aliyun.oss.accessKeySecret}")
//    private String accessKeySecret;
//    @Value("${aliyun.oss.bucketName}")
//    private String bucketName;@Autowiredprivate AliOSSProperties aliOSSProperties;/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws IOException {// 获取阿里云OSS参数String endpoint = aliOSSProperties.getEndpoint();String accessKeyId = aliOSSProperties.getAccessKeyId();String accessKeySecret = aliOSSProperties.getAccessKeySecret();String bucketName = aliOSSProperties.getBucketName();// 获取上传的文件的输入流InputStream inputStream = file.getInputStream();// 避免文件覆盖String originalFilename = file.getOriginalFilename();String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));//上传文件到 OSSOSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);ossClient.putObject(bucketName, fileName, inputStream);//文件访问路径String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;// 关闭ossClientossClient.shutdown();return url;// 把上传到oss的路径返回}}

10、全局异常处理类GlobalExceptionHandler

package com.bocai.exception;import com.bocai.common.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** =========================全局异常处理器========================*/
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)//捕获所有异常public Result ex(Exception ex){ex.printStackTrace();return Result.error("对不起,操作失败,请联系管理员");}}

11、拦截器LoginCheckInterceptor

package com.bocai.interceptor;import com.alibaba.fastjson.JSONObject;
import com.bocai.common.Result;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import java.util.Map;/***   =========================LoginCheckInterceptor 拦截器 interceptor========================*/
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //目标资源方法运行前运行, 返回true: 放行, 放回false, 不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {//1.获取请求url。String url = req.getRequestURL().toString();log.info("请求的url: {}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行。if(url.contains("login")){log.info("登录操作, 放行...");return true;}//3.获取请求头中的令牌( Authorization)。String jwt = req.getHeader("Authorization");//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。if(!StringUtils.hasLength(jwt)){log.info("请求头Authorization为空,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json --------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return false;}//5.解析token,如果解析失败,返回错误结果(未登录)。try {Map<String, Object> claims = JwtUtils.parseJWT(jwt);//6.把业务数据存储到ThreadLocal中ThreadLocalUtil.set(claims);//7.放行。log.info("令牌合法, 放行");return true;} catch (Exception e) {//jwt解析失败e.printStackTrace();log.info("解析令牌失败, 返回未登录错误信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json --------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return false;}}@Override //目标资源方法运行后运行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle ...");}@Override //视图渲染完毕后运行, 最后运行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清空ThreadLocal中的数据,防止内存泄漏ThreadLocalUtil.remove();System.out.println("afterCompletion...");}
}

12、配置类

 12.1 配置类WebConfig注册拦截器

package com.bocai.config;import com.bocai.interceptor.LoginCheckInterceptor;
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;/***   =========================LoginCheckInterceptor 的配置类 ========================*/
@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;/*** 注册拦截器, 拦截所有url,除登录* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login","/user/register");}
}

12.2   MybatisPlus分页配置类MybatisPlusConfig

package com.bocai.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 配置MP的分页插件*/
@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){// 1、定义MybatisPlus拦截器MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();// 2、添加分页的拦截器mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 3、添加乐观锁的拦截器mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor;}
}

13、自定义注解(新增文章)

13.1 新增文章自定义注解State接口

package com.bocai.anno;import com.bocai.validation.StateValidation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.constraints.NotEmpty;import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;@Documented//元注解
@Target({ FIELD})//元注解
@Retention(RUNTIME)//元注解
@Constraint(validatedBy = { StateValidation.class})//指定提供校验规则的类
public @interface State {//提供校验失败后的提示信息String message() default "state参数的值只能是已发布或者草稿";//指定分组Class<?>[] groups() default { };//负载  获取到State注解的附加信息Class<? extends Payload>[] payload() default { };
}

13.2 新增文章自定义注解实现类StateValidation

package com.bocai.validation;import com.bocai.anno.State;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;public class StateValidation implements ConstraintValidator<State,String> {/**** @param value 将来要校验的数据* @param context context in which the constraint is evaluated** @return 如果返回false,则校验不通过,如果返回true,则校验通过*/@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {//提供校验规则if (value == null){return false;}if (value.equals("已发布") || value.equals("草稿")){return true;}return false;}
}

14、封装分页实体PageBean

package com.bocai.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;/*** 分页查询结果封装类*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {private Long total;//总记录数private List items;//数据列表}

二、用户

1、注册

1.1 UserController

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username,password);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}}

1.2 service

package com.bocai.service;import com.bocai.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service
* @createDate 2023-11-13 19:54:41
*/
public interface UserService extends IService<User> {/*** 用户注册* @param username* @param password*/void register(String username, String password);/*** 根据用户名 --查询用户* @param username  * @return*/User queryUserByUsername(String username);
}

1.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.mapper.UserMapper;
import com.bocai.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2023-11-13 19:54:41
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate UserMapper userMapper;/*** 注册* @param username* @param password*/@Overridepublic void register(String username, String password) {//密码加密String md5String = Md5Util.getMD5String(password);User user = new User();user.setUsername(username);user.setPassword(md5String);user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}/*** 查询用户* @param username    * @return*/@Overridepublic User queryUserByUsername(String username) {//查询用户LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(username != null, User::getUsername,username);User user = userMapper.selectOne(lambdaQueryWrapper);return user;}
}

2、登录

2.1 UserController

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.Md5Util;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功return Result.success("JWT");}return Result.error("密码错误!");}
}

2.2 登录认证 

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.mapper.UserMapper;
import com.bocai.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2023-11-13 19:54:41
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate UserMapper userMapper;/*** 注册* @param username* @param password*/@Overridepublic void register(String username, String password) {//密码加密String md5String = Md5Util.getMD5String(password);User user = new User();user.setUsername(username);user.setPassword(md5String);user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}/*** 查询用户* @param username* @return*/@Overridepublic User queryUserByUsername(String username) {//查询用户LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(username != null, User::getUsername,username);User user = userMapper.selectOne(lambdaQueryWrapper);return user;}
}

3、获取用户详细信息

3.1 UserController

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.Md5Util;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功Map<String, Object> claims = new HashMap<>();claims.put("id", loginUser.getId());claims.put("username",loginUser.getUsername());String jwt = JwtUtils.generateJwt(claims); //让jwt包含了当前登录的员工信息return Result.success(jwt);}return Result.error("密码错误!");}/*** 查询用户信息(从token获取)* @param token* @return*/@GetMapping("/userInfo")public Result userInfo(@RequestHeader(name = "Authorization")String token){log.info("查询用户全部信息");//根据用户名查询用户Map<String, Object> claims = JwtUtils.parseJWT(token);String username = (String) claims.get("username");User user = userService.queryUserByUsername(username);return Result.success(user);}
}

 3.2 servcie

package com.bocai.service;import com.bocai.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service
* @createDate 2023-11-13 19:54:41
*/
public interface UserService extends IService<User> {/*** 用户注册* @param username* @param password*/void register(String username, String password);/*** 根据用户名 --查询用户* @param username* @return*/User queryUserByUsername(String username);/*** 更新用户* @param user*/void updateUser(User user);}

3.3 servcieImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.mapper.UserMapper;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2023-11-13 19:54:41
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate UserMapper userMapper;/*** 注册* @param username* @param password*/@Overridepublic void register(String username, String password) {//密码加密String md5String = Md5Util.getMD5String(password);User user = new User();user.setUsername(username);user.setPassword(md5String);user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}/*** 查询用户* @param username* @return*/@Overridepublic User queryUserByUsername(String username) {//查询用户LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(username != null, User::getUsername,username);User user = userMapper.selectOne(lambdaQueryWrapper);return user;}/*** 更新用户* @param user*/@Overridepublic void updateUser(User user) {user.setUpdateTime(LocalDateTime.now());userMapper.updateById(user);}}

3.4 优化版本UserController(使用ThreadLocal)

 

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功Map<String, Object> claims = new HashMap<>();claims.put("id", loginUser.getId());claims.put("username",loginUser.getUsername());String jwt = JwtUtils.generateJwt(claims); //让jwt包含了当前登录的员工信息return Result.success(jwt);}return Result.error("密码错误!");}/*** 查询用户信息(从线程获取)* @return*/@GetMapping("/userInfo")public Result userInfo(){// 从线程获取存储的jwt信息Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");log.info("查询用户全部信息,从token获取信息为:{}",username);//根据用户名查询用户User user = userService.queryUserByUsername(username);return Result.success(user);}//使用上面的的优化版本
//    /**
//     * 查询用户信息(从token获取)
//     * @param token
//     * @return
//     */
//    @GetMapping("/userInfo")
//    public Result userInfo(@RequestHeader(name = "Authorization")String token){
//        log.info("查询用户全部信息,从token获取信息为:{}",token);
//        //根据用户名查询用户
//        Map<String, Object> claims = JwtUtils.parseJWT(token);
//        String username = (String) claims.get("username");
//        User user = userService.queryUserByUsername(username);
//        return Result.success(user);
//    }
}

4、更新用户基本信息

4.1 UserController

@Validated

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功Map<String, Object> claims = new HashMap<>();claims.put("id", loginUser.getId());claims.put("username",loginUser.getUsername());String jwt = JwtUtils.generateJwt(claims); //让jwt包含了当前登录的员工信息return Result.success(jwt);}return Result.error("密码错误!");}/*** 查询用户信息(从线程获取)* @return*/@GetMapping("/userInfo")public Result userInfo(){// 从线程获取存储的jwt信息Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");log.info("查询用户全部信息,从token获取信息为:{}",username);//根据用户名查询用户User user = userService.queryUserByUsername(username);return Result.success(user);}//使用上面的的优化版本
//    /**
//     * 查询用户信息(从token获取)
//     * @param token
//     * @return
//     */
//    @GetMapping("/userInfo")
//    public Result userInfo(@RequestHeader(name = "Authorization")String token){
//        log.info("查询用户全部信息,从token获取信息为:{}",token);
//        //根据用户名查询用户
//        Map<String, Object> claims = JwtUtils.parseJWT(token);
//        String username = (String) claims.get("username");
//        User user = userService.queryUserByUsername(username);
//        return Result.success(user);
//    }/*** 更新用户* @param user* @return*/@PutMapping("/update")public Result update(@RequestBody @Validated  User user){log.info("修改的用户为:{}",user);userService.updateUser(user);return Result.success();}
}

4.2 servcie

package com.bocai.service;import com.bocai.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service
* @createDate 2023-11-13 19:54:41
*/
public interface UserService extends IService<User> {/*** 用户注册* @param username* @param password*/void register(String username, String password);/*** 根据用户名 --查询用户* @param username* @return*/User queryUserByUsername(String username);/*** 更新用户* @param user*/void updateUser(User user);}

4.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.mapper.UserMapper;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2023-11-13 19:54:41
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate UserMapper userMapper;/*** 注册* @param username* @param password*/@Overridepublic void register(String username, String password) {//密码加密String md5String = Md5Util.getMD5String(password);User user = new User();user.setUsername(username);user.setPassword(md5String);user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}/*** 查询用户* @param username* @return*/@Overridepublic User queryUserByUsername(String username) {//查询用户LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(username != null, User::getUsername,username);User user = userMapper.selectOne(lambdaQueryWrapper);return user;}/*** 更新用户* @param user*/@Overridepublic void updateUser(User user) {user.setUpdateTime(LocalDateTime.now());userMapper.updateById(user);}}

5、更新用户头像

5.2 UserController 

本内容2个知识点:

1、@URL 判断传参是不是url

2、@PatchMapping

@PutMapping和@PatchMapping是Spring MVC中用于处理HTTP请求的注解,它们在功能和使用上有一些区别。

  1. 请求方式:@PutMapping用于处理PUT请求,而@PatchMapping用于处理PATCH请求。
  2. 请求范围:@PutMapping通常用于执行大规模的替换操作,而不是更新操作。如果省略了订单上的某个属性,那么该属性的值应该被NULL所替代,甚至订单中的某个物品的实体数据也应一起重新设置,否则它们将从订单中移除。而@PatchMapping则用于对资源的部分更新,即只更新请求中指定的属性或关系。
  3. 参数绑定:@PutMapping可以使用@RequestBody注解将请求体中的JSON数据映射到Java对象中,而@PatchMapping则无法直接使用@RequestBody注解,需要使用其他方式来解析请求体中的JSON数据。
package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功Map<String, Object> claims = new HashMap<>();claims.put("id", loginUser.getId());claims.put("username",loginUser.getUsername());String jwt = JwtUtils.generateJwt(claims); //让jwt包含了当前登录的员工信息return Result.success(jwt);}return Result.error("密码错误!");}/*** 查询用户信息(从线程获取)* @return*/@GetMapping("/userInfo")public Result userInfo(){// 从线程获取存储的jwt信息Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");log.info("查询用户全部信息,从token获取信息为:{}",username);//根据用户名查询用户User user = userService.queryUserByUsername(username);return Result.success(user);}//使用上面的的优化版本
//    /**
//     * 查询用户信息(从token获取)
//     * @param token
//     * @return
//     */
//    @GetMapping("/userInfo")
//    public Result userInfo(@RequestHeader(name = "Authorization")String token){
//        log.info("查询用户全部信息,从token获取信息为:{}",token);
//        //根据用户名查询用户
//        Map<String, Object> claims = JwtUtils.parseJWT(token);
//        String username = (String) claims.get("username");
//        User user = userService.queryUserByUsername(username);
//        return Result.success(user);
//    }/*** 更新用户* @param user* @return*/@PutMapping("/update")public Result update(@RequestBody @Validated  User user){log.info("修改的用户为:{}",user);userService.updateUser(user);return Result.success();}/*** 更新头像* @param avatarUrl* @return*/@PatchMapping("/updateAvatar")public Result updateAvatar(@RequestParam @URL String avatarUrl){log.info("头像地址是{}",avatarUrl);userService.updateAvatar(avatarUrl);return Result.success();}
}

5.2 servcie

package com.bocai.service;import com.bocai.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service
* @createDate 2023-11-13 19:54:41
*/
public interface UserService extends IService<User> {/*** 用户注册* @param username* @param password*/void register(String username, String password);/*** 根据用户名 --查询用户* @param username* @return*/User queryUserByUsername(String username);/*** 更新用户* @param user*/void updateUser(User user);/*** 更新头像* @param avatarUrl*/void updateAvatar(String avatarUrl);}

5.3 servcieImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.mapper.UserMapper;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2023-11-13 19:54:41
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate UserMapper userMapper;/*** 注册* @param username* @param password*/@Overridepublic void register(String username, String password) {//密码加密String md5String = Md5Util.getMD5String(password);User user = new User();user.setUsername(username);user.setPassword(md5String);user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}/*** 查询用户* @param username* @return*/@Overridepublic User queryUserByUsername(String username) {//查询用户LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(username != null, User::getUsername,username);User user = userMapper.selectOne(lambdaQueryWrapper);return user;}/*** 更新用户* @param user*/@Overridepublic void updateUser(User user) {user.setUpdateTime(LocalDateTime.now());userMapper.updateById(user);}/*** 更新头像* @param avatarUrl*/@Overridepublic void updateAvatar(String avatarUrl) {Map<String, Object> map = ThreadLocalUtil.get();Integer id = (Integer) map.get("id");User user = new User();user.setId(id);user.setUpdateTime(LocalDateTime.now());user.setUserPic(avatarUrl);userMapper.updateById(user);}}

6、更新用户密码

6.1 UserController

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功Map<String, Object> claims = new HashMap<>();claims.put("id", loginUser.getId());claims.put("username",loginUser.getUsername());String jwt = JwtUtils.generateJwt(claims); //让jwt包含了当前登录的员工信息return Result.success(jwt);}return Result.error("密码错误!");}/*** 查询用户信息(从线程获取)* @return*/@GetMapping("/userInfo")public Result userInfo(){// 从线程获取存储的jwt信息Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");log.info("查询用户全部信息,从token获取信息为:{}",username);//根据用户名查询用户User user = userService.queryUserByUsername(username);return Result.success(user);}//使用上面的的优化版本
//    /**
//     * 查询用户信息(从token获取)
//     * @param token
//     * @return
//     */
//    @GetMapping("/userInfo")
//    public Result userInfo(@RequestHeader(name = "Authorization")String token){
//        log.info("查询用户全部信息,从token获取信息为:{}",token);
//        //根据用户名查询用户
//        Map<String, Object> claims = JwtUtils.parseJWT(token);
//        String username = (String) claims.get("username");
//        User user = userService.queryUserByUsername(username);
//        return Result.success(user);
//    }/*** 更新用户* @param user* @return*/@PutMapping("/update")public Result update(@RequestBody @Validated  User user){log.info("修改的用户为:{}",user);userService.updateUser(user);return Result.success();}/*** 更新头像* @param avatarUrl* @return*/@PatchMapping("/updateAvatar")public Result updateAvatar(@RequestParam @URL String avatarUrl){log.info("头像地址是{}",avatarUrl);userService.updateAvatar(avatarUrl);return Result.success();}/*** 更新密码* @param params json数据包含old_pwd,new_pwd,re_pwd* @return*/@PatchMapping("/updatePwd")public Result updatePwd(@RequestBody Map<String, String> params){log.info("修改密码传过来数据是:{}",params);// 1、校验参数String old_pwd = params.get("old_pwd");String new_pwd = params.get("new_pwd");String re_pwd = params.get("re_pwd");if(!StringUtils.hasLength(old_pwd) || !StringUtils.hasLength(new_pwd) || !StringUtils.hasLength(re_pwd)){return Result.error("缺少必要参数!");}//原密码是否正确Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");User loginUser = userService.queryUserByUsername(username);if(!loginUser.getPassword().equals(Md5Util.getMD5String(old_pwd))){return Result.error("原密码不正确!");}//新、老密码是否一致if(old_pwd.equals(new_pwd)){return Result.error("新、老密码一样!!");}//新密码和确认密码不一致!if(!re_pwd.equals(new_pwd)){return Result.error("新密码和确认密码不一致!!");}// 2 、调用userServiceuserService.updatePwd(new_pwd);return Result.success();}
}

6.2 service

package com.bocai.service;import com.bocai.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service
* @createDate 2023-11-13 19:54:41
*/
public interface UserService extends IService<User> {/*** 用户注册* @param username* @param password*/void register(String username, String password);/*** 根据用户名 --查询用户* @param username* @return*/User queryUserByUsername(String username);/*** 更新用户* @param user*/void updateUser(User user);/*** 更新头像* @param avatarUrl*/void updateAvatar(String avatarUrl);/*** 更新密码* @param newPwd*/void updatePwd(String newPwd);
}

6.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.mapper.UserMapper;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;/**
* @author cheng
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2023-11-13 19:54:41
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate UserMapper userMapper;/*** 注册* @param username* @param password*/@Overridepublic void register(String username, String password) {//密码加密String md5String = Md5Util.getMD5String(password);User user = new User();user.setUsername(username);user.setPassword(md5String);user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}/*** 查询用户* @param username* @return*/@Overridepublic User queryUserByUsername(String username) {//查询用户LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(username != null, User::getUsername,username);User user = userMapper.selectOne(lambdaQueryWrapper);return user;}/*** 更新用户* @param user*/@Overridepublic void updateUser(User user) {user.setUpdateTime(LocalDateTime.now());userMapper.updateById(user);}/*** 更新头像* @param avatarUrl*/@Overridepublic void updateAvatar(String avatarUrl) {Map<String, Object> map = ThreadLocalUtil.get();Integer id = (Integer) map.get("id");User user = new User();user.setId(id);user.setUpdateTime(LocalDateTime.now());user.setUserPic(avatarUrl);userMapper.updateById(user);}/*** 更新密码* @param newPwd*/@Overridepublic void updatePwd(String newPwd) {Map<String, Object> map = ThreadLocalUtil.get();Integer id = (Integer) map.get("id");User user = new User();user.setId(id);user.setUpdateTime(LocalDateTime.now());user.setPassword(Md5Util.getMD5String(newPwd));userMapper.updateById(user);}
}

三、文章分类

1、新增文章分类

1.1 CategoryController

@Validated

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.Category;
import com.bocai.pojo.User;
import com.bocai.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
@RequestMapping("/category")
public class CategoryController {@Autowiredprivate CategoryService categoryService;/*** 添加文章分类* @param category* @return*/@PostMappingpublic Result add(@RequestBody @Validated(Category.Add.class) Category category){log.info("新增的文章为:{}",category);// 查询文章分类是否已被创建Category queryCategory = categoryService.queryCategoryByCategoryName(category);if (queryCategory == null){//文章分类没有被创建categoryService.add(category);return Result.success();}else{return Result.error("文章分类被占用,不能创建重复");}}}

1.2 service

package com.bocai.service;import com.bocai.pojo.Category;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【category】的数据库操作Service
* @createDate 2023-11-13 19:55:04
*/
public interface CategoryService extends IService<Category> {/*** 新增文章分类* @param category*/void add(Category category);/*** 根据分类名称查询文章分类* @param category* @return*/Category queryCategoryByCategoryName(Category category);
}

1.3 servcieImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Category;
import com.bocai.service.CategoryService;
import com.bocai.mapper.CategoryMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.Map;/**
* @author cheng
* @description 针对表【category】的数据库操作Service实现
* @createDate 2023-11-13 19:55:04
*/
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>implements CategoryService{@Autowiredprivate CategoryMapper categoryMapper;/*** 新增文章分类* @param category*/@Overridepublic void add(Category category) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");category.setCreateTime(LocalDateTime.now());category.setUpdateTime(LocalDateTime.now());category.setCreateUser(createUserId);categoryMapper.insert(category);}/*** 根据传入参数判断当前对象是否在对象中存在* @param category* @return*/@Overridepublic Category queryCategoryByCategoryName(Category category) {LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(category.getCategoryName() != null, Category::getCategoryName,category.getCategoryName()).ne(category.getId() != null, Category::getId,category.getId()) ;Category queryCategory = categoryMapper.selectOne(lambdaQueryWrapper);return queryCategory;}
}

2、文章分类列表

2.1 CategoryController

1、实体类Category指定日期返回格式   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

2、实体类Category   @JsonIgnore // json返回不显示

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.Category;
import com.bocai.pojo.User;
import com.bocai.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@Slf4j
@RequestMapping("/category")
public class CategoryController {@Autowiredprivate CategoryService categoryService;/*** 添加文章分类* @param category* @return*/@PostMappingpublic Result add(@RequestBody @Validated(Category.Add.class) Category category){log.info("新增的文章为:{}",category);// 查询文章分类是否已被创建Category queryCategory = categoryService.queryCategoryByCategoryName(category);if (queryCategory == null){//文章分类没有被创建categoryService.add(category);return Result.success();}else{return Result.error("文章分类被占用,不能创建重复");}}/*** 列表查询当前登录用户创建的文章分类* @return*/@GetMappingpublic Result list(){log.info("列表查询当前登录用户创建的文章分类");List list = categoryService.categorylist();return Result.success(list);}}

2.2 service

package com.bocai.service;import com.bocai.pojo.Category;
import com.baomidou.mybatisplus.extension.service.IService;import java.util.List;/**
* @author cheng
* @description 针对表【category】的数据库操作Service
* @createDate 2023-11-13 19:55:04
*/
public interface CategoryService extends IService<Category> {/*** 新增文章分类* @param category*/void add(Category category);/*** 根据分类名称查询文章分类* @param category* @return*/Category queryCategoryByCategoryName(Category category);/*** 列表查询当前登录用户创建的文章分类* @return*/List categorylist();
}

2.3 servcieImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Category;
import com.bocai.service.CategoryService;
import com.bocai.mapper.CategoryMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;/**
* @author cheng
* @description 针对表【category】的数据库操作Service实现
* @createDate 2023-11-13 19:55:04
*/
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>implements CategoryService{@Autowiredprivate CategoryMapper categoryMapper;/*** 新增文章分类* @param category*/@Overridepublic void add(Category category) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");category.setCreateTime(LocalDateTime.now());category.setUpdateTime(LocalDateTime.now());category.setCreateUser(createUserId);categoryMapper.insert(category);}/*** 根据传入参数判断当前对象是否在对象中存在* @param category* @return*/@Overridepublic Category queryCategoryByCategoryName(Category category) {LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(category.getCategoryName() != null, Category::getCategoryName,category.getCategoryName()).ne(category.getId() != null, Category::getId,category.getId()) ;Category queryCategory = categoryMapper.selectOne(lambdaQueryWrapper);return queryCategory;}/*** 列表查询当前登录用户创建的文章分类* @return*/@Overridepublic List categorylist() {Map<String, Object> map = ThreadLocalUtil.get();Integer userId = (Integer) map.get("id");LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(userId != null,Category::getCreateUser,userId);return categoryMapper.selectList(lambdaQueryWrapper);}
}

3、 获取文章分类详情

3.1 CategoryController

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.Category;
import com.bocai.pojo.User;
import com.bocai.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@Slf4j
@RequestMapping("/category")
public class CategoryController {@Autowiredprivate CategoryService categoryService;/*** 添加文章分类* @param category* @return*/@PostMappingpublic Result add(@RequestBody @Validated(Category.Add.class) Category category){log.info("新增的文章为:{}",category);// 查询文章分类是否已被创建Category queryCategory = categoryService.queryCategoryByCategoryName(category);if (queryCategory == null){//文章分类没有被创建categoryService.add(category);return Result.success();}else{return Result.error("文章分类被占用,不能创建重复");}}/*** 列表查询当前登录用户创建的文章分类* @return*/@GetMappingpublic Result list(){log.info("列表查询当前登录用户创建的文章分类");List list = categoryService.categorylist();return Result.success(list);}/*** 根据id查询文章分类* @param id* @return*/@GetMapping("/detail")public Result detail(Integer id){log.info("查询ID为:{}文章分类详情",id);Category category = categoryService.queryCategoryById(id);return Result.success(category);}}

3.2 service

package com.bocai.service;import com.bocai.pojo.Category;
import com.baomidou.mybatisplus.extension.service.IService;import java.util.List;/**
* @author cheng
* @description 针对表【category】的数据库操作Service
* @createDate 2023-11-13 19:55:04
*/
public interface CategoryService extends IService<Category> {/*** 新增文章分类* @param category*/void add(Category category);/*** 根据分类名称查询文章分类* @param category* @return*/Category queryCategoryByCategoryName(Category category);/*** 列表查询当前登录用户创建的文章分类* @return*/List categorylist();/*** 根据id查询文章分类* @param id* @return*/Category queryCategoryById(Integer id);
}

3.3 servcieImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Category;
import com.bocai.service.CategoryService;
import com.bocai.mapper.CategoryMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;/**
* @author cheng
* @description 针对表【category】的数据库操作Service实现
* @createDate 2023-11-13 19:55:04
*/
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>implements CategoryService{@Autowiredprivate CategoryMapper categoryMapper;/*** 新增文章分类* @param category*/@Overridepublic void add(Category category) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");category.setCreateTime(LocalDateTime.now());category.setUpdateTime(LocalDateTime.now());category.setCreateUser(createUserId);categoryMapper.insert(category);}/*** 根据传入参数判断当前对象是否在对象中存在* @param category* @return*/@Overridepublic Category queryCategoryByCategoryName(Category category) {LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(category.getCategoryName() != null, Category::getCategoryName,category.getCategoryName()).ne(category.getId() != null, Category::getId,category.getId()) ;Category queryCategory = categoryMapper.selectOne(lambdaQueryWrapper);return queryCategory;}/*** 列表查询当前登录用户创建的文章分类* @return*/@Overridepublic List categorylist() {Map<String, Object> map = ThreadLocalUtil.get();Integer userId = (Integer) map.get("id");LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(userId != null,Category::getCreateUser,userId);return categoryMapper.selectList(lambdaQueryWrapper);}/*** 根据id查询文章分类* @param id* @return*/@Overridepublic Category queryCategoryById(Integer id) {return  categoryMapper.selectById(id);}
}

4、更新文章分类

4.1 CategoryController

分组校验,这里主要原因是实体id字段新增不需要验证,修改需要验证。

在实体类进行修改,然后在CategoryController指定使用哪个分组

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.Category;
import com.bocai.pojo.User;
import com.bocai.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@Slf4j
@RequestMapping("/category")
public class CategoryController {@Autowiredprivate CategoryService categoryService;/*** 添加文章分类* @param category* @return*/@PostMappingpublic Result add(@RequestBody @Validated(Category.Add.class) Category category){log.info("新增的文章为:{}",category);// 查询文章分类是否已被创建Category queryCategory = categoryService.queryCategoryByCategoryName(category);if (queryCategory == null){//文章分类没有被创建categoryService.add(category);return Result.success();}else{return Result.error("文章分类被占用,不能创建重复");}}/*** 列表查询当前登录用户创建的文章分类* @return*/@GetMappingpublic Result list(){log.info("列表查询当前登录用户创建的文章分类");List list = categoryService.categorylist();return Result.success(list);}/*** 根据id查询文章分类* @param id* @return*/@GetMapping("/detail")public Result detail(Integer id){log.info("查询ID为:{}文章分类详情",id);Category category = categoryService.queryCategoryById(id);return Result.success(category);}/*** 根据id修改文章分类* @param category* @return*/@PutMappingpublic Result update(@RequestBody @Validated(Category.Update.class) Category category) {log.info("修改的文章分类为:{}", category);// 查询文章分类是否已被创建Category queryCategory = categoryService.queryCategoryByCategoryName(category);if (queryCategory == null){//文章分类没有重复categoryService.updateCategoryById(category);return Result.success();}else{return Result.error("文章分类被占用,不能修改为重复");}}}

4.2 service

package com.bocai.service;import com.bocai.pojo.Category;
import com.baomidou.mybatisplus.extension.service.IService;import java.util.List;/**
* @author cheng
* @description 针对表【category】的数据库操作Service
* @createDate 2023-11-13 19:55:04
*/
public interface CategoryService extends IService<Category> {/*** 新增文章分类* @param category*/void add(Category category);/*** 根据分类名称查询文章分类* @param category* @return*/Category queryCategoryByCategoryName(Category category);/*** 列表查询当前登录用户创建的文章分类* @return*/List categorylist();/*** 根据id查询文章分类* @param id* @return*/Category queryCategoryById(Integer id);/*** 根据id修改文章分类* @param category*/void updateCategoryById(Category category);
}

4.3 servcieImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Category;
import com.bocai.service.CategoryService;
import com.bocai.mapper.CategoryMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;/**
* @author cheng
* @description 针对表【category】的数据库操作Service实现
* @createDate 2023-11-13 19:55:04
*/
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>implements CategoryService{@Autowiredprivate CategoryMapper categoryMapper;/*** 新增文章分类* @param category*/@Overridepublic void add(Category category) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");category.setCreateTime(LocalDateTime.now());category.setUpdateTime(LocalDateTime.now());category.setCreateUser(createUserId);categoryMapper.insert(category);}/*** 根据传入参数判断当前对象是否在对象中存在* @param category* @return*/@Overridepublic Category queryCategoryByCategoryName(Category category) {LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(category.getCategoryName() != null, Category::getCategoryName,category.getCategoryName()).ne(category.getId() != null, Category::getId,category.getId()) ;Category queryCategory = categoryMapper.selectOne(lambdaQueryWrapper);return queryCategory;}/*** 列表查询当前登录用户创建的文章分类* @return*/@Overridepublic List categorylist() {Map<String, Object> map = ThreadLocalUtil.get();Integer userId = (Integer) map.get("id");LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(userId != null,Category::getCreateUser,userId);return categoryMapper.selectList(lambdaQueryWrapper);}/*** 根据id查询文章分类* @param id* @return*/@Overridepublic Category queryCategoryById(Integer id) {return  categoryMapper.selectById(id);}/*** 根据id修改文章分类* @param category*/@Overridepublic void updateCategoryById(Category category) {category.setUpdateTime(LocalDateTime.now());categoryMapper.updateById(category);}
}

5、删除文章分类

5.1 CategoryController

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.Category;
import com.bocai.pojo.User;
import com.bocai.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@Slf4j
@RequestMapping("/category")
public class CategoryController {@Autowiredprivate CategoryService categoryService;/*** 添加文章分类* @param category* @return*/@PostMappingpublic Result add(@RequestBody @Validated(Category.Add.class) Category category){log.info("新增的文章为:{}",category);// 查询文章分类是否已被创建Category queryCategory = categoryService.queryCategoryByCategoryName(category);if (queryCategory == null){//文章分类没有被创建categoryService.add(category);return Result.success();}else{return Result.error("文章分类被占用,不能创建重复");}}/*** 列表查询当前登录用户创建的文章分类* @return*/@GetMappingpublic Result list(){log.info("列表查询当前登录用户创建的文章分类");List list = categoryService.categorylist();return Result.success(list);}/*** 根据id查询文章分类* @param id* @return*/@GetMapping("/detail")public Result detail(Integer id){log.info("查询ID为:{}文章分类详情",id);Category category = categoryService.queryCategoryById(id);return Result.success(category);}/*** 根据id修改文章分类* @param category* @return*/@PutMappingpublic Result update(@RequestBody @Validated(Category.Update.class) Category category) {log.info("修改的文章分类为:{}", category);// 查询文章分类是否已被创建Category queryCategory = categoryService.queryCategoryByCategoryName(category);if (queryCategory == null){//文章分类没有重复categoryService.updateCategoryById(category);return Result.success();}else{return Result.error("文章分类被占用,不能修改为重复");}}/*** 根据id删除文章分类* @param id* @return*/@DeleteMappingpublic Result delete(Integer id){log.info("根据id删除文章分类{}",id);categoryService.deleteCategoryById(id);return Result.success();}}

5.2 service

package com.bocai.service;import com.bocai.pojo.Category;
import com.baomidou.mybatisplus.extension.service.IService;import java.util.List;/**
* @author cheng
* @description 针对表【category】的数据库操作Service
* @createDate 2023-11-13 19:55:04
*/
public interface CategoryService extends IService<Category> {/*** 新增文章分类* @param category*/void add(Category category);/*** 根据分类名称查询文章分类* @param category* @return*/Category queryCategoryByCategoryName(Category category);/*** 列表查询当前登录用户创建的文章分类* @return*/List categorylist();/*** 根据id查询文章分类* @param id* @return*/Category queryCategoryById(Integer id);/*** 根据id修改文章分类* @param category*/void updateCategoryById(Category category);/*** 根据id删除文章分类* @param id*/void deleteCategoryById(Integer id);
}

5.3 servcieImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Category;
import com.bocai.service.CategoryService;
import com.bocai.mapper.CategoryMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;/**
* @author cheng
* @description 针对表【category】的数据库操作Service实现
* @createDate 2023-11-13 19:55:04
*/
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>implements CategoryService{@Autowiredprivate CategoryMapper categoryMapper;/*** 新增文章分类* @param category*/@Overridepublic void add(Category category) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");category.setCreateTime(LocalDateTime.now());category.setUpdateTime(LocalDateTime.now());category.setCreateUser(createUserId);categoryMapper.insert(category);}@Overridepublic Category queryCategoryByCategoryName(String categoryName) {LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(categoryName != null, Category::getCategoryName,categoryName);Category category = categoryMapper.selectOne(lambdaQueryWrapper);return category;}/*** 列表查询当前登录用户创建的文章分类* @return*/@Overridepublic List categorylist() {Map<String, Object> map = ThreadLocalUtil.get();Integer userId = (Integer) map.get("id");LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(userId != null,Category::getCreateUser,userId);return categoryMapper.selectList(lambdaQueryWrapper);}/*** 根据id查询文章分类* @param id* @return*/@Overridepublic Category queryCategoryById(Integer id) {return  categoryMapper.selectById(id);}/*** 根据id修改文章分类* @param category*/@Overridepublic void updateCategoryById(Category category) {category.setUpdateTime(LocalDateTime.now());categoryMapper.updateById(category);}/*** 根据id删除文章分类* @param id*/@Overridepublic void deleteCategoryById(Integer id) {categoryMapper.deleteById(id);}
}

四、文章管理

1、新增文章

1.1 ArticleCtroller

自定义校验

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j
@RequestMapping("/article")
public class ArticleCtroller {@Autowiredprivate ArticleService articleService;/*** 添加文章* @param article* @return*/@PostMappingpublic Result add(@RequestBody @Validated Article article){log.info("新增文章为:{}",article);//查询文章标题是否被创建Article queryArticle = articleService.queryArticleByTitle(article);if(queryArticle == null){//没有重复的文章标题articleService.add(article);return Result.success();}else {// 存在重复文章标题return Result.error("文章标题重复!");}}
}

1.2 service

package com.bocai.service;import com.bocai.pojo.Article;
import com.baomidou.mybatisplus.extension.service.IService;/**
* @author cheng
* @description 针对表【article】的数据库操作Service
* @createDate 2023-11-13 19:55:11
*/
public interface ArticleService extends IService<Article> {/*** 新增文章* @param article*/void add(Article article);/*** 根据文章标题查询文章* @param article* @return*/Article queryArticleByTitle(Article article);
}

1.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.service.ArticleService;
import com.bocai.mapper.ArticleMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.Map;/**
* @author cheng
* @description 针对表【article】的数据库操作Service实现
* @createDate 2023-11-13 19:55:11
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>implements ArticleService{@Autowiredprivate ArticleMapper articleMapper;/*** 新增文章* @param article*/@Overridepublic void add(Article article) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");article.setCreateUser(createUserId);article.setCreateTime(LocalDateTime.now());article.setUpdateTime(LocalDateTime.now());articleMapper.insert(article);}/*** 根据文章标题查询文章* @param article* @return*/@Overridepublic Article queryArticleByTitle(Article article) {LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(article.getTitle() != null, Article::getTitle,article.getTitle()).ne(article.getId() != null,Article::getId,article.getId());return articleMapper.selectOne(lambdaQueryWrapper);}
}

2、文章列表(条件分页)

2.1 ArticleCtroller

package com.bocai.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bocai.common.Result;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.Emp;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.time.LocalDate;@RestController
@Slf4j
@RequestMapping("/article")
public class ArticleCtroller {@Autowiredprivate ArticleService articleService;/*** 添加文章* @param article* @return*/@PostMappingpublic Result add(@RequestBody @Validated Article article){log.info("新增文章为:{}",article);//查询文章标题是否被创建Article queryArticle = articleService.queryArticleByTitle(article);if(queryArticle == null){//没有重复的文章标题articleService.add(article);return Result.success();}else {// 存在重复文章标题return Result.error("文章标题重复!");}}/*** 文章根据条件查询,并分页* @param pageNum* @param pageSize* @param categoryId* @param state* @return*/@GetMappingpublic Result page(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,String categoryId, String state){log.info("分页查询参数:当前页:{} 每页条数: {} 文章分类ID:{}  状态:{} ",pageNum,pageSize,categoryId,state);PageBean pageBean = articleService.pageList(pageNum,pageSize,categoryId,state);return Result.success(pageBean);}
}

2.2 service

package com.bocai.service;import com.bocai.pojo.Article;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bocai.pojo.PageBean;/**
* @author cheng
* @description 针对表【article】的数据库操作Service
* @createDate 2023-11-13 19:55:11
*/
public interface ArticleService extends IService<Article> {/*** 新增文章* @param article*/void add(Article article);/*** 根据文章标题查询文章* @param article* @return*/Article queryArticleByTitle(Article article);/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state);
}

2.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import com.bocai.mapper.ArticleMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.Map;/**
* @author cheng
* @description 针对表【article】的数据库操作Service实现
* @createDate 2023-11-13 19:55:11
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>implements ArticleService{@Autowiredprivate ArticleMapper articleMapper;/*** 新增文章* @param article*/@Overridepublic void add(Article article) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");article.setCreateUser(createUserId);article.setCreateTime(LocalDateTime.now());article.setUpdateTime(LocalDateTime.now());articleMapper.insert(article);}/*** 根据文章标题查询文章* @param article* @return*/@Overridepublic Article queryArticleByTitle(Article article) {LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(article.getTitle() != null, Article::getTitle,article.getTitle()).ne(article.getId() != null,Article::getId,article.getId());return articleMapper.selectOne(lambdaQueryWrapper);}/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/@Overridepublic PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state) {Map<String,Object> map = ThreadLocalUtil.get();String userId = (String) map.get("id");LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(categoryId != null,Article::getCategoryId,categoryId).eq(state != null,Article::getState,state).eq(userId != null,Article::getCreateUser,userId);Page<Article> pageArticle = new Page<>(pageNum,pageSize);articleMapper.selectPage(pageArticle,lambdaQueryWrapper);PageBean pageBean = new PageBean(pageArticle.getTotal(),pageArticle.getRecords());return pageBean;}
}

3、获取文章详情

3.1 ArticleCtroller

package com.bocai.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bocai.common.Result;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.Emp;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.time.LocalDate;@RestController
@Slf4j
@RequestMapping("/article")
public class ArticleCtroller {@Autowiredprivate ArticleService articleService;/*** 添加文章* @param article* @return*/@PostMappingpublic Result add(@RequestBody @Validated Article article){log.info("新增文章为:{}",article);//查询文章标题是否被创建String articleTitle = article.getTitle();Article queryArticle = articleService.queryArticleByTitle(articleTitle);if(queryArticle == null){//没有重复的文章标题articleService.add(article);return Result.success();}else {// 存在重复文章标题return Result.error("文章标题重复!");}}/*** 文章根据条件查询,并分页* @param pageNum* @param pageSize* @param categoryId* @param state* @return*/@GetMappingpublic Result page(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,String categoryId, String state){log.info("分页查询参数:当前页:{} 每页条数: {} 文章分类ID:{}  状态:{} ",pageNum,pageSize,categoryId,state);PageBean pageBean = articleService.pageList(pageNum,pageSize,categoryId,state);return Result.success(pageBean);}/*** 文章详情* @param id* @return*/@GetMapping("/detail")public Result detail(Integer id){log.info("文章id{}详情",id);Article article = articleService.detail(id);return Result.success(article);}
}

3.2 service

package com.bocai.service;import com.bocai.pojo.Article;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bocai.pojo.PageBean;/**
* @author cheng
* @description 针对表【article】的数据库操作Service
* @createDate 2023-11-13 19:55:11
*/
public interface ArticleService extends IService<Article> {/*** 新增文章* @param article*/void add(Article article);/*** 根据文章标题查询文章* @param articleTitle* @return*/Article queryArticleByTitle(String articleTitle);/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state);/*** 文章详情* @param id* @return*/Article detail(Integer id);
}

3.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import com.bocai.mapper.ArticleMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.Map;/**
* @author cheng
* @description 针对表【article】的数据库操作Service实现
* @createDate 2023-11-13 19:55:11
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>implements ArticleService{@Autowiredprivate ArticleMapper articleMapper;/*** 新增文章* @param article*/@Overridepublic void add(Article article) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");article.setCreateUser(createUserId);article.setCreateTime(LocalDateTime.now());article.setUpdateTime(LocalDateTime.now());articleMapper.insert(article);}/*** 根据文章标题查询文章* @param articleTitle* @return*/@Overridepublic Article queryArticleByTitle(String articleTitle) {LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(articleTitle != null, Article::getTitle,articleTitle);return articleMapper.selectOne(lambdaQueryWrapper);}/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/@Overridepublic PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state) {Map<String,Object> map = ThreadLocalUtil.get();String userId = (String) map.get("id");LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(categoryId != null,Article::getCategoryId,categoryId).eq(state != null,Article::getState,state).eq(userId != null,Article::getCreateUser,userId);Page<Article> pageArticle = new Page<>(pageNum,pageSize);articleMapper.selectPage(pageArticle,lambdaQueryWrapper);PageBean pageBean = new PageBean(pageArticle.getTotal(),pageArticle.getRecords());return pageBean;}/*** 文章详情* @param id* @return*/@Overridepublic Article detail(Integer id) {return articleMapper.selectById(id);}
}

4、更新文章

4.1 ArticleCtroller

package com.bocai.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bocai.common.Result;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.Emp;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.time.LocalDate;@RestController
@Slf4j
@RequestMapping("/article")
public class ArticleCtroller {@Autowiredprivate ArticleService articleService;/*** 添加文章* @param article* @return*/@PostMappingpublic Result add(@RequestBody @Validated(Article.Add.class) Article article){log.info("新增文章为:{}",article);//查询文章标题是否被创建Article queryArticle = articleService.queryArticleByTitle(article);if(queryArticle == null){//没有重复的文章标题articleService.add(article);return Result.success();}else {// 存在重复文章标题return Result.error("文章标题重复!");}}/*** 文章根据条件查询,并分页* @param pageNum* @param pageSize* @param categoryId* @param state* @return*/@GetMappingpublic Result page(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,String categoryId, String state){log.info("分页查询参数:当前页:{} 每页条数: {} 文章分类ID:{}  状态:{} ",pageNum,pageSize,categoryId,state);PageBean pageBean = articleService.pageList(pageNum,pageSize,categoryId,state);return Result.success(pageBean);}/*** 文章详情* @param id* @return*/@GetMapping("/detail")public Result detail(Integer id){log.info("文章id{}详情",id);Article article = articleService.detail(id);return Result.success(article);}/*** 根据id更新文章* @param article* @return*/@PutMappingpublic Result update(@RequestBody @Validated(Article.Update.class) Article article){log.info("根据id更新文章这些属性{}",article);Article queryArticle = articleService.queryArticleByTitle(article);if(queryArticle == null){articleService.updateArticleById(article);return Result.success();}else {return Result.error("不能修改为文章标题重复名称");}}
}

4.2 service

package com.bocai.service;import com.bocai.pojo.Article;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bocai.pojo.PageBean;/**
* @author cheng
* @description 针对表【article】的数据库操作Service
* @createDate 2023-11-13 19:55:11
*/
public interface ArticleService extends IService<Article> {/*** 新增文章* @param article*/void add(Article article);/*** 根据文章标题查询文章* @param article* @return*/Article queryArticleByTitle(Article article);/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state);/*** 文章详情* @param id* @return*/Article detail(Integer id);/***     根据id更新文章* @param article*/void updateArticleById(Article article);
}

4.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import com.bocai.mapper.ArticleMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.Map;/**
* @author cheng
* @description 针对表【article】的数据库操作Service实现
* @createDate 2023-11-13 19:55:11
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>implements ArticleService{@Autowiredprivate ArticleMapper articleMapper;/*** 新增文章* @param article*/@Overridepublic void add(Article article) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");article.setCreateUser(createUserId);article.setCreateTime(LocalDateTime.now());article.setUpdateTime(LocalDateTime.now());articleMapper.insert(article);}/*** 根据文章标题查询文章* @param article* @return*/@Overridepublic Article queryArticleByTitle(Article article) {LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(article.getTitle() != null, Article::getTitle,article.getTitle()).ne(article.getId() != null,Article::getId,article.getId());return articleMapper.selectOne(lambdaQueryWrapper);}/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/@Overridepublic PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state) {Map<String,Object> map = ThreadLocalUtil.get();String userId = (String) map.get("id");LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(categoryId != null,Article::getCategoryId,categoryId).eq(state != null,Article::getState,state).eq(userId != null,Article::getCreateUser,userId);Page<Article> pageArticle = new Page<>(pageNum,pageSize);articleMapper.selectPage(pageArticle,lambdaQueryWrapper);PageBean pageBean = new PageBean(pageArticle.getTotal(),pageArticle.getRecords());return pageBean;}/*** 文章详情* @param id* @return*/@Overridepublic Article detail(Integer id) {return articleMapper.selectById(id);}/*** 根据id更新文章* @param article*/@Overridepublic void updateArticleById(Article article) {article.setUpdateTime(LocalDateTime.now());articleMapper.updateById(article);}
}

5、删除文章

5.1 ArticleCtroller

package com.bocai.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bocai.common.Result;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.Emp;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.time.LocalDate;@RestController
@Slf4j
@RequestMapping("/article")
public class ArticleCtroller {@Autowiredprivate ArticleService articleService;/*** 添加文章* @param article* @return*/@PostMappingpublic Result add(@RequestBody @Validated(Article.Add.class) Article article){log.info("新增文章为:{}",article);//查询文章标题是否被创建Article queryArticle = articleService.queryArticleByTitle(article);if(queryArticle == null){//没有重复的文章标题articleService.add(article);return Result.success();}else {// 存在重复文章标题return Result.error("文章标题重复!");}}/*** 文章根据条件查询,并分页* @param pageNum* @param pageSize* @param categoryId* @param state* @return*/@GetMappingpublic Result page(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,String categoryId, String state){log.info("分页查询参数:当前页:{} 每页条数: {} 文章分类ID:{}  状态:{} ",pageNum,pageSize,categoryId,state);PageBean pageBean = articleService.pageList(pageNum,pageSize,categoryId,state);return Result.success(pageBean);}/*** 文章详情* @param id* @return*/@GetMapping("/detail")public Result detail(Integer id){log.info("文章id{}详情",id);Article article = articleService.detail(id);return Result.success(article);}/*** 根据id更新文章* @param article* @return*/@PutMappingpublic Result update(@RequestBody @Validated(Article.Update.class) Article article){log.info("根据id更新文章这些属性{}",article);Article queryArticle = articleService.queryArticleByTitle(article);if(queryArticle == null){articleService.updateArticleById(article);return Result.success();}else {return Result.error("不能修改为文章标题重复名称");}}/*** 根据id删除文章* @param id* @return*/@DeleteMappingpublic Result delete(Integer id){log.info("根据id{},删除文章",id);articleService.deleteArticleById(id);return Result.success();}
}

5.2 service

package com.bocai.service;import com.bocai.pojo.Article;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bocai.pojo.PageBean;/**
* @author cheng
* @description 针对表【article】的数据库操作Service
* @createDate 2023-11-13 19:55:11
*/
public interface ArticleService extends IService<Article> {/*** 新增文章* @param article*/void add(Article article);/*** 根据文章标题查询文章* @param article* @return*/Article queryArticleByTitle(Article article);/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state);/*** 文章详情* @param id* @return*/Article detail(Integer id);/***     根据id更新文章* @param article*/void updateArticleById(Article article);/*** 根据id删除文章* @param id*/void deleteArticleById(Integer id);
}

5.3 serviceImpl

package com.bocai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocai.pojo.Article;
import com.bocai.pojo.Category;
import com.bocai.pojo.PageBean;
import com.bocai.service.ArticleService;
import com.bocai.mapper.ArticleMapper;
import com.bocai.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.Map;/**
* @author cheng
* @description 针对表【article】的数据库操作Service实现
* @createDate 2023-11-13 19:55:11
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>implements ArticleService{@Autowiredprivate ArticleMapper articleMapper;/*** 新增文章* @param article*/@Overridepublic void add(Article article) {Map<String, Object> map = ThreadLocalUtil.get();Integer createUserId = (Integer) map.get("id");article.setCreateUser(createUserId);article.setCreateTime(LocalDateTime.now());article.setUpdateTime(LocalDateTime.now());articleMapper.insert(article);}/*** 根据文章标题查询文章* @param article* @return*/@Overridepublic Article queryArticleByTitle(Article article) {LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(article.getTitle() != null, Article::getTitle,article.getTitle()).ne(article.getId() != null,Article::getId,article.getId());return articleMapper.selectOne(lambdaQueryWrapper);}/*** 文章根据条件查询,并分页* @param pageNum 当前页码* @param pageSize 每页条数* @param categoryId 文章分类ID* @param state 状态* @return*/@Overridepublic PageBean pageList(Integer pageNum, Integer pageSize, String categoryId, String state) {Map<String,Object> map = ThreadLocalUtil.get();String userId = (String) map.get("id");LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(categoryId != null,Article::getCategoryId,categoryId).eq(state != null,Article::getState,state).eq(userId != null,Article::getCreateUser,userId);Page<Article> pageArticle = new Page<>(pageNum,pageSize);articleMapper.selectPage(pageArticle,lambdaQueryWrapper);PageBean pageBean = new PageBean(pageArticle.getTotal(),pageArticle.getRecords());return pageBean;}/*** 文章详情* @param id* @return*/@Overridepublic Article detail(Integer id) {return articleMapper.selectById(id);}/*** 根据id更新文章* @param article*/@Overridepublic void updateArticleById(Article article) {article.setUpdateTime(LocalDateTime.now());articleMapper.updateById(article);}/*** 根据id删除文章* @param id*/@Overridepublic void deleteArticleById(Integer id) {articleMapper.deleteById(id);}
}

五、上传接口

1、FileUploadController

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.utils.AliOSSUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;@RestController
@Slf4j
public class FileUploadController {@Autowiredprivate AliOSSUtils aliOSSUtils;@PostMapping("/upload")public Result upload(MultipartFile file) throws IOException {log.info("上传的文件名:{}",file.getOriginalFilename());String url = aliOSSUtils.upload(file);return Result.success(url);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/192486.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

降低城市内涝风险,万宾科技内涝积水监测仪的作用

频繁的内涝会削弱和损坏城市的关键基础设施&#xff0c;包括道路、桥梁和公用设施。城市内涝风险降低可以减少交通中断事件&#xff0c;也可以保护居民安全并降低路面维修等成本&#xff0c;进一步确保城市基本服务继续发挥作用。对城市可持续发展来讲有效减少内涝的风险是重要…

Ubuntu环境下以编译源码的方式安装Vim

目录 1. Ubuntu环境 2. 下载编译vim 2.1 效果截图 3. 配置环境变量 1. Ubuntu环境 Linux chris-166 6.2.0-36-generic #37~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon Oct 9 15:34:04 UTC 2 x86_64 x86_64 x86_64 GNU/Linux 2. 下载编译vim // 源码下载 chris_166chris-16…

职场新人,如何提高自我管理能力?

作为职场新人&#xff0c;一定要学会个人管理。 入职三个月多&#xff0c;我总结了一个经验&#xff0c;作为职场新人&#xff0c;我越加觉得自我管理重要性。 在职场一个普遍的现象&#xff1a;在领导眼里&#xff0c;同样的问题在老职员身上不是问题&#xff0c;在新员工身…

灰度图处理方法

做深度学习项目图像处理的时候常常涉及到灰度图处理&#xff0c;这里对自己处理灰度图的方式做一个记录&#xff0c;后续有更新的话会在此更新 一&#xff0c;多维数组可视化 将多维数组可视化为灰度图 img_gray Image.fromarray(img, modeL) # 实现array到image的转换,m…

Elasticsearch 作为 GenAI 缓存层

作者&#xff1a;JEFF VESTAL&#xff0c;BAHA AZARMI 探索如何将 Elasticsearch 集成为缓存层&#xff0c;通过降低 token 成本和响应时间来优化生成式 AI 性能&#xff0c;这已通过实际测试和实际实施进行了证明。 随着生成式人工智能 (GenAI) 不断革新从客户服务到数据分析…

最强大模型训练芯片H200发布!141G大内存,AI推理最高提升90%,还兼容H100

梦晨 克雷西 发自 凹非寺 量子位 | 公众号 QbitAI 英伟达老黄&#xff0c;带着新一代GPU芯片H200再次炸场。 官网毫不客气就直说了&#xff0c;“世界最强GPU&#xff0c;专为AI和超算打造”。 听说所有AI公司都抱怨内存不够&#xff1f; 这回直接141GB大内存&#xff0c;与…

Vatee万腾智能创新探索:Vatee科技引领创新发展

在Vatee万腾的智能创新探索中&#xff0c;我们见证了一场科技领域的革命。Vatee万腾通过其独到的智能时代愿景&#xff0c;正引领着科技创新发展的浪潮&#xff0c;塑造着未来的数字化格局。 Vatee万腾以其卓越的科技引领力&#xff0c;将智能创新推向新的高度。通过整合先进的…

建筑楼宇智慧能源管理系统,轻松解决能源管理问题

随着科技的进步与人们节能减排意识的不断增强&#xff0c;建筑楼宇是当下节能减排的重要工具。通过能源管理平台解决能效管理、降低用能成本、一体化管控、精细化管理和服务提供有力支撑。 建筑楼宇智慧能源管理系统是一种利用先进手段&#xff0c;采用微服务架构&#xff0c;…

小米智能电视投屏方法

小米智能电视也提供了投屏功能。 使用遥控器&#xff0c;在应用中找到它&#xff0c;点击进入。 小米电视支持windows笔记本&#xff0c;macbook笔记本&#xff0c;iphone手机&#xff0c;安卓手机投屏。 windows笔记本投屏 在投屏应用中找到windows投屏&#xff0c;选中开…

【ML】欠拟合和过拟合的一些判别和优化方法(吴恩达机器学习笔记)

吴恩达老师的机器学习教程笔记 减少误差的一些方法 获得更多的训练实例——解决高方差尝试减少特征的数量——解决高方差尝试获得更多的特征——解决高偏差尝试增加多项式特征——解决高偏差尝试减少正则化程度 λ——解决高偏差尝试增加正则化程度 λ——解决高方差 什么是…

python用pychart库,实现将经纬度信息在地图上显示

python使用pyecharts对给到的经纬度数据进行位置标注&#xff0c;下面是批量更新。给入数据&#xff0c;将地图生成。实验数据在下面附件。 from pyecharts import options as opts from pyecharts.charts import Geo import osfolder_path F:\\GPS file_names os.listdir(f…

gmpy2 GMP is_prime函数底层c代码分析

偶然看到一篇paper&#xff08;2018年发表&#xff09;&#xff0c;说GMP中的素性检测使用的是单独的Miller_Rabin方法&#xff0c;单独的Miller_Rabin素性检测会存在部分安全问题&#xff08;低概率&#xff09;&#xff0c;然后突然想求证一下最新版本的GMP中是否进行了修改。…

Ansible playbook详解

playbook是ansible用于配置&#xff0c;部署&#xff0c;和被管理被控节点的剧本 playbook常用的YMAL格式&#xff1a;&#xff08;文件名称以 .yml结尾&#xff09; 1、文件的第一行应该以 "---" (三个连字符)开始&#xff0c;表明YMAL文件的开始。    2、在同一…

如何把小米路由器刷入OpenWRT系统并通过内网穿透工具实现公网远程访问

小米路由器4A千兆版刷入OpenWRT并远程访问 文章目录 小米路由器4A千兆版刷入OpenWRT并远程访问前言1. 安装Python和需要的库2. 使用 OpenWRTInvasion 破解路由器3. 备份当前分区并刷入新的Breed4. 安装cpolar内网穿透4.1 注册账号4.2 下载cpolar客户端4.3 登录cpolar web ui管理…

11.10 知识总结(数据的增删改查、如何创建表关系、Django框架的请求生命周期流程图)

一、 数据的增删改查 1.1 用户列表的展示 把数据表中得用户数据都给查询出来展示在页面上 添加数据 id username password gender age action 修改 删除 1.2 修…

44. Adb调试QT开发的Android程序实用小技巧汇总

1. 说明 使用QT开发Android应用时,如果程序本身出现了问题,很难进行调试。不像在linux或者windows系统中,可以利用QtCreator软件本身进行一些调试,安卓应用一旦在系统中安装后,如果运行中途出现什么BUG,定位问题所在很麻烦。不过,好在有adb这种调试工具可以代替QtCreat…

【数据结构】反射、枚举

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 反射、枚举 1. 反射1.1 定义1.2 反射…

数据结构上机实验——图的实现(以无向邻接表为例)、图的深度优先搜索(DFS)、图的广度优先搜索(BFS)

文章目录 数据结构上机实验1.要求2.图的实现&#xff08;以无向邻接表为例&#xff09;2.1创建图2.1.1定义图的顶点、边及类定义2.1.2创建无向图和查找2.1.3插入边2.1.4打印函数 2.2图的深度优先搜索&#xff08;DFS&#xff09;2.3图的广度优先搜索&#xff08;BFS&#xff09…

为什么PDF文件不能打印?

正常的PDF文件是可以打印的&#xff0c;如果PDF文件打开之后发现文件不能打印&#xff0c;我们需要先查看一下自己的打印机是否能够正常运行&#xff0c;如果打印机是正常的&#xff0c;我们再查看一下&#xff0c;文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功…

使用vue2实现todolist待办事项

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…