前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Daily-Blog项目前台日志

Daily-Blog项目前台日志

作者头像
用户11097514
发布2024-05-30 21:33:35
发布2024-05-30 21:33:35
25000
代码可运行
举报
文章被收录于专栏:技术分享技术分享
运行总次数:0
代码可运行

daily- blog项目

快速搭建项目

创建完数据库对应的表 等操作之后,进入idea

使用EasyCode快速创建工程

  1. 首先连接数据库
  2. 然后在对应的表上点击,然后GeneraleCode
  3. 如果想要删除表名中的前缀 ,就可以使用removePre
  4. 创建包、实体类、dao等都可以自动生成

自动生成的代码修改

根据自己的需求,修改相应的代码 比如 : 删除其中的继承东西等

我们这里暂时不做任何修改

接下来就是修改实体类对应的信息

比如: 我们需要添加实体类与数据库中表的对应关系用 @TableName("sg_article") , 对于主键自增的字段使用@TableId

代码语言:javascript
代码运行次数:0
复制
/**
 * 文章表(Article)表实体类
 *
 * @author Ray2310
 * @since 2023-03-11 09:42:17
 */
@SuppressWarnings("serial")
@TableName("sg_article")
public class Article {

    @TableId
    private Long id;
    //标题
    private String title;
    //文章内容
    private String content;
    //文章摘要
    private String summary;
    //所属分类id
    private Long categoryId;
    //缩略图
    private String thumbnail;
    //是否置顶(0否,1是)
    private String isTop;
    //状态(0已发布,1草稿)
    private String status;
    //访问量
    private Long viewCount;
    //是否允许评论 1是,0否
    private String isComment;

    private Long createBy;

    private Date createTime;

    private Long updateBy;

    private Date updateTime;
    //删除标志(0代表未删除,1代表已删除)
    private Integer delFlag;
}

修改service、dao等层

对于Mapper层 ,因为使用的是Mybatis-plus,所以使用的Mapper就方便很多

代码语言:javascript
代码运行次数:0
复制
public interface ArticleMapper extends BaseMapper<Article> {
}

service层

代码语言:javascript
代码运行次数:0
复制
public interface ArticleService extends IService<Article> {
}

impl实现类上加注解

代码语言:javascript
代码运行次数:0
复制
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
}

配置Controller及其注意事项

Controller层

代码语言:javascript
代码运行次数:0
复制
@RestController
@RequestMapping("/article")
public class ArticleController {
    @Resource
    private ArticleService articleService;

    @GetMapping("/list")
    public List<Article> test(){
        List<Article> list = articleService.list();
        return list;
    }
}

注意事项:

对于使用模块化项目,我们再配置完成后需要重新install项目,这样不同模块配置的内容才会加载出来

image-20230311101949457
image-20230311101949457

表的设计分析

image-20230311102627224
image-20230311102627224

通用的响应实体类 和 响应枚举

代码语言:javascript
代码运行次数:0
复制
package com.blog.domain;

import com.blog.enums.AppHttpCodeEnum;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;

/**
 * 响应类
 * @param <T>
 * @author Ray2310
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> implements Serializable {
    private Integer code;
    private String msg;
    private T data;

    public ResponseResult() {
        this.code = AppHttpCodeEnum.SUCCESS.getCode();
        this.msg = AppHttpCodeEnum.SUCCESS.getMsg();
    }

    public ResponseResult(Integer code, T data) {
        this.code = code;
        this.data = data;
    }

    public ResponseResult(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public ResponseResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public static ResponseResult errorResult(int code, String msg) {
        ResponseResult result = new ResponseResult();
        return result.error(code, msg);
    }
    public static ResponseResult okResult() {
        ResponseResult result = new ResponseResult();
        return result;
    }
    public static ResponseResult okResult(int code, String msg) {
        ResponseResult result = new ResponseResult();
        return result.ok(code, null, msg);
    }

    public static ResponseResult okResult(Object data) {
        ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg());
        if(data!=null) {
            result.setData(data);
        }
        return result;
    }

    public static ResponseResult errorResult(AppHttpCodeEnum enums){
        return setAppHttpCodeEnum(enums,enums.getMsg());
    }

    public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg){
        return setAppHttpCodeEnum(enums,msg);
    }

    public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums){
        return okResult(enums.getCode(),enums.getMsg());
    }

    private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg){
        return okResult(enums.getCode(),msg);
    }

    public ResponseResult<?> error(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
        return this;
    }

    public ResponseResult<?> ok(Integer code, T data) {
        this.code = code;
        this.data = data;
        return this;
    }

    public ResponseResult<?> ok(Integer code, T data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
        return this;
    }

    public ResponseResult<?> ok(T data) {
        this.data = data;
        return this;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }



}
代码语言:javascript
代码运行次数:0
复制
package com.blog.enums;

/**
 * 专门存放枚举的类
 */
public enum AppHttpCodeEnum {
    // 成功
    SUCCESS(200,"操作成功"),
    // 登录
    NEED_LOGIN(401,"需要登录后操作"),
    NO_OPERATOR_AUTH(403,"无权限操作"),
    SYSTEM_ERROR(500,"出现错误"),
    USERNAME_EXIST(501,"用户名已存在"),
     PHONENUMBER_EXIST(502,"手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"),
    REQUIRE_USERNAME(504, "必需填写用户名"),
    CONTENT_NOT_NULL(506, "评论内容不能为空"),
    FILE_TYPE_ERROR(507, "文件类型错误,请上传png文件"),
    USERNAME_NOT_NULL(508, "用户名不能为空"),
    NICKNAME_NOT_NULL(509, "昵称不能为空"),
    PASSWORD_NOT_NULL(510, "密码不能为空"),
    EMAIL_NOT_NULL(511, "邮箱不能为空"),
    NICKNAME_EXIST(512, "昵称已存在"),
    LOGIN_ERROR(505,"用户名或密码错误");
    int code;
    String msg;

    AppHttpCodeEnum(int code, String errorMessage){
        this.code = code;
        this.msg = errorMessage;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

调用前端接口时出现权限不够

image-20230311130111226
image-20230311130111226

同时会出现无法显示的问题, 那是因为我们前后端不在同一个域中,需要在mvc配置文件中配置跨域连调

代码语言:javascript
代码运行次数:0
复制
@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 实现跨域配置
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 设置允许跨域的路径
        registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOriginPatterns("*")
                // 是否允许cookie
                .allowCredentials(true)
                // 设置允许的请求方式
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                // 设置允许的header属性
                .allowedHeaders("*")
                // 跨域允许时间
                .maxAge(3600);
    }

}

博客前台

热门文章列表

image-20230311102117772
image-20230311102117772

需求

查询出浏览量最高的前10篇文章的信息。 要求展示文章标题和浏览量。八能够让用户自己点击跳转到具体的文章详请进行浏览

注意 : 不要把草稿展示出来 ,不要把删除的文章查询出来

接口设计

将返回值使用 通用的返回响应

controller层

代码语言:javascript
代码运行次数:0
复制
//todo 查询热门文章
@GetMapping("/hotArticleList")
public ResponseResult hotArticleList(){
    //查询热门文章,然后封装成ResponseResult ,然后返回
    return articleService.hotArticleList();
}

service层实现

代码语言:javascript
代码运行次数:0
复制
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {


    //todo 查询热门文章
    /*需求:
    查询出浏览量最高的前10篇文章的信息。 要求展览示文章标题和浏量。八能够让用户自己点击跳转到具体的文章详请进行浏览
    注意 :`不要把草稿展示出来 ,不要把删除的文章查询出来`
     */
    @Override
    public ResponseResult hotArticleList() {
        //查询热门文章 封装返回
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        //用 LambdaQueryWrapper 写查询条件
        queryWrapper.eq(Article::getStatus,0);
        queryWrapper.orderByDesc(Article::getViewCount);
        Page<Article> page = new Page(1,10);
        //判空
        if (ObjectUtils.isEmpty(page)){
            return ResponseResult.errorResult(AppHttpCodeEnum.valueOf("暂无热门文章"));
        }
        page(page,queryWrapper);
        List<Article> articles = page.getRecords();

        return ResponseResult.okResult(articles);
    }
}

这里老师的代码有错误,分页没有被加进去 ,我们自己需要修改

使用VO优化

image-20230311141200213
image-20230311141200213

需求 : 从我们的出的接口的返回值我们就可以看出,我们需要的只是博客内容的访问量 以及 博客名 而不是所有的内容都返回。这样不仅会造成信息泄露 ,如果文章字数过多,还会造成内存额外消耗。所以我们需要进行优化

经过处理的类我们叫做 VO类型的类

代码语言:javascript
代码运行次数:0
复制
/**
 * 接口文档中要去响应回去的字段
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HotArticle {
    //文章id
    private Long id;
    //文章标题
    private String title;
    //访问量
    private Long viewCount;
}

然后再通过类型拷贝,就可以将我们需要的数据返回,而不是返回所有【拷贝的原理是两个类的属性相同】

代码语言:javascript
代码运行次数:0
复制
List<Article> articles = page.getRecords();
List<HotArticle> hotArticles = new ArrayList<>();
// 类的赋值拷贝 Article中的某些字段 ---> HotArticle
//使用BeanUtils进行拷贝
for (Article article : articles){
    HotArticle vo = new HotArticle();
    BeanUtils.copyProperties(article,vo);
    hotArticles.add(vo);
}
return ResponseResult.okResult(hotArticles);

封装Bean拷贝工具类

代码语言:javascript
代码运行次数:0
复制
/**
 * 有关拷贝工具类的封装
 * @author Ray2310
 */
public class BeanCopyUtils {

    private BeanCopyUtils(){
    }

    /**
     * 实现属性拷贝
     * @param source
     * @param clazz
     * @return
     */
    public static <V> V copyBean(Object source,Class<V> clazz){
        //利用反射创建目标对象
        V result = null;
        try {
            result = clazz.newInstance();
            //实现属性的拷贝
            BeanUtils.copyProperties(source,result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回结果
        return result;
    }

    /**
     * 如果是list集合的属性拷贝 ,就直接调用该方法
     * @param list 源列表
     * @param clazz 目标对象
     * @param <V> 需要转换的类型的泛型
     * @return 返回转换后的集合
     */
    public static  <O,V> List<V> copyBeanList(List<O> list , Class<V> clazz ){
        List<V> collect = list.stream()
                .map(o -> copyBean(o, clazz))
                .collect(Collectors.toList());
        return collect;
    }
}

分类列表需求

image-20230311145817223
image-20230311145817223

需求

页面上需要展示分类列表, 用户可以通过点击具体的分类查看该分类下的文章列表。

注意: 1. 要求只展示有发布展示文章的分类 。 2. 必须是正常状态的分类

表信息

image-20230311150302648
image-20230311150302648

接口设计

image-20230311151015334
image-20230311151015334
代码语言:javascript
代码运行次数:0
复制
@RequestMapping("/category")
@RestController
public class CategoryController {

    @Resource
    private CategoryService categoryService;

    //todo 分类请求
    @GetMapping("/getCategoryList")
    public ResponseResult getCategoryList(){
        return categoryService.getCategoryList();
    }
}

思路:

  1. 先在文章表中查询 status(文章发布or未发布)为 0 的,也就是发布了的 。还有就是未删除的
  2. 查出上一步的之后只需要查分类id就可以了(category_id)
  3. 然后再到category表中查出对应的名称即可

实现

首先我们使用EasyCode生成对应的mapper、pojo实体类等

完成service层等的代码实现

代码语言:javascript
代码运行次数:0
复制
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    @Resource
    private ArticleService articleService;


    //todo 分类请求
    @Override
    public ResponseResult getCategoryList() {
        //1. 先在文章表中查询 status(文章发布or未发布)为 0 的,也就是发布了的 。还有就是未删除的
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_PUT);
        List<Article> articles = articleService.list(queryWrapper);
        //2. 查出上一步的之后只需要查分类id就可以了(category_id)
        //todo 函数式编程 ,用来将查询到的id查询category
        Set<Long> categoryIds = articles.stream()
                .map(new Function<Article, Long>() {
                    @Override
                    public Long apply(Article article) {
                        return article.getCategoryId();
                    }
                }).collect(Collectors.toSet());
        //3. 然后再到category表中查出对应的名称即可 ,还需要判断分类的状态是正常的
        List<Category> categories = listByIds(categoryIds);
        //4. 判断分类的状态是正常的
        List<Category> collect = categories.stream().filter(category -> category.getStatus().equals(SystemConstants.ARTICLE_CATEGORY_STATUS)).collect(Collectors.toList());
        //5. 封装状态
        List<CategoryVo> categoryVoList = BeanCopyUtils.copyBeanList(collect, CategoryVo.class);

        return ResponseResult.okResult(categoryVoList);
    }
}
注意点: 了解函数式编程

分页查询文章列表

需求

在首页查询文章页面都有文章列表 ,首页 :查询所有文章

分类页面: 查询对应分类的文章列表

要求 ::1. 只能查询正式发布的文章 2. 置顶文章要显示在最前面

接口设计

image-20230312143807864
image-20230312143807864

实现

代码语言:javascript
代码运行次数:0
复制
//todo 文章分页
@GetMapping("/articleList")
//如果在请求路径后面直接 /+值的 需要使用 @PathVariable
//如果是从请求体中获取出来的就需要加上 @RequestBody
public ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId){

    return articleService.articleList(pageNum,pageSize,categoryId);
}

按照要求 ,我们需要将查询到的信息传入前端, 但是 不能将全部信息传入 ,所以就需要将查询到的信息进行封装

List<ArticleListVo> articleListVo = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleListVo.class);

代码语言:javascript
代码运行次数:0
复制
//todo 文章分页
/*
在首页查询文章页面都有文章列表  ,首页 :查询所有文章
分类页面: 查询对应分类的文章列表
要求 ::1. 只能查询正式发布的文章 2. 置顶文章要显示在最前面
 */
@Override
public ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId) {
    LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper();
    //如果有categoryId ,那么查询和传入的就需要相同
    queryWrapper.eq(Objects.nonNull(categoryId) && categoryId > 0,Article::getCategoryId,categoryId);

    //状态 : 正式发布
    queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_PUT);
    //置顶的文章(对isTop进行排序)
    queryWrapper.orderByDesc(Article::getIsTop);
    //分页查询
    Page<Article> pageN = new Page<>(pageNum,pageSize);
    Page<Article> page = page(pageN, queryWrapper);
    //封装查询结果
    List<ArticleListVo> articleListVo = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleListVo.class);
    PageVo pageVo = new PageVo(articleListVo, page.getTotal());
    return ResponseResult.okResult(pageVo);
}

因为我们封装的是categoryName,但是查询出来的确实categoryId,所以需要在查询后进行给categoryName赋值

代码语言:javascript
代码运行次数:0
复制
for (Article article  : records){
    Category category = categoryService.getById(article.getCategoryId());
    article.setCategoryName(category.getName());
}
分页配置
代码语言:javascript
代码运行次数:0
复制
/**
 * myBatisPlus分页配置
 */
@Configuration
public class MyBatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mb = new MybatisPlusInterceptor();
        mb.addInnerInterceptor(new PaginationInnerInterceptor());
        return mb;
    }
}
修改时间格式配置

在WebConfig中

代码语言:javascript
代码运行次数:0
复制
//todo 修改时间格式 【yyyy-MM-dd HH:mm:ss】 
// 其实也可以直接在相关字段上加注解
// @JsonFormat(timezone="GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
// 只是这样做可以使所有的时间格式都转换
@Bean//使用@Bean注入fastJsonHttpMessageConvert
public HttpMessageConverter fastJsonHttpMessageConverters() {
    //1.需要定义一个Convert转换消息的对象
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
    fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");

   // SerializeConfig.globalInstance.put(Long.class, ToStringSerializer.instance);

    fastJsonConfig.setSerializeConfig(SerializeConfig.globalInstance);
    fastConverter.setFastJsonConfig(fastJsonConfig);
    HttpMessageConverter<?> converter = fastConverter;
    return converter;
}

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(fastJsonHttpMessageConverters());
}

文章详情接口

需求

要在文章列表页面点击阅读全文时能够跳转到文章详情页面 ,可以让用户阅读文章正文

要求: 1. 要在文章详情中展示其分类名

接口信息

image-20230312164517847
image-20230312164517847

响应格式

image-20230312164556027
image-20230312164556027

实现

代码语言:javascript
代码运行次数:0
复制
//todo 查询文章详情
  @GetMapping("/{id}")
  public ResponseResult getArticleDetails(@PathVariable("id") Long id){
      return articleService.getArticleDetails(id);
  }
代码语言:javascript
代码运行次数:0
复制
//todo 查询文章详情
/*
要在文章列表页面点击阅读全文时能够跳转到文章详情页面 ,可以让用户阅读文章正文
要求: 1. 要在文章详情中展示其分类名
 */
@Override
public ResponseResult getArticleDetails(Long id) {
    //根据文章id查询文章
    Article article = getById(id);
    //转换成vo格式
    ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
    //根据分类id查询分类名
    Long categoryId = articleDetailVo.getCategoryId();
    Category category = categoryService.getById(categoryId);
    if(category == null){
        return ResponseResult.okResult(articleDetailVo);
    }
    articleDetailVo.setCategoryName(category.getName());
    //封装响应,返回
    return ResponseResult.okResult(articleDetailVo);
}

友链查询

需求

如果进行评论 ,那么就可以将用户的网站名、地址、描述、logo放上去

接口设计

image-20230312170340390
image-20230312170340390

响应格式

image-20230312170721528
image-20230312170721528

表信息

image-20230312170447017
image-20230312170447017

实现

代码语言:javascript
代码运行次数:0
复制
@RestController
@RequestMapping("/link")
public class LinkController {
    @Resource
    private LinkService linkService;

    //todo 获取所有友链
    @GetMapping("/getAllLink")
    public ResponseResult getAllLink(){
        return linkService.getAllLink();
    }

}
代码语言:javascript
代码运行次数:0
复制
@Service("linkService")
public class LinkServiceImpl extends ServiceImpl<LinkMapper, Link> implements LinkService {

    // todo 获取所有友链
    /*
     如果进行评论 ,那么就可以将用户的网站名、地址、描述、logo放上去
     */
    @Override
    public ResponseResult getAllLink() {
        //查询所有审核通过的
        LambdaQueryWrapper<Link> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(Link::getStatus, SystemConstants.LINK_STATUS_NORMAL);
        List<Link> links = list(queryWrapper);

        List<LinkVo> linkVos = BeanCopyUtils.copyBeanList(links, LinkVo.class);
        return ResponseResult.okResult(linkVos);
    }
}

评论列表

接口

image-20230316110227487
image-20230316110227487
image-20230316110924073
image-20230316110924073

响应

image-20230316112155537
image-20230316112155537

需求

不仅需要实现评论 ,还要实现”父子评论“

表分析

image-20230316110441239
image-20230316110441239

实现

代码语言:javascript
代码运行次数:0
复制
@RestController
@RequestMapping("/comment")
public class CommentController {


    @Autowired
    private CommentService commentService;

    //todo 评论列表
    @GetMapping("/commentList")
    public ResponseResult commentList(Long articleId ,Integer pageNum , Integer pageSize){
        return commentService.commentList(articleId,pageNum,pageSize);
    }

}

service层

代码语言:javascript
代码运行次数:0
复制
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Resource
    private UserService userService;

    //todo 评论列表
    @Override
    public ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize) {
        //根据文章id 所对应的 根评论(root_id = -1)
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        //对articleId进行判断
        queryWrapper.eq(Comment::getArticleId,articleId);
        queryWrapper.eq(Comment::getRootId, SystemConstants.ARTICLE_ROOT_COMMENT);
        //分页查询
        Page<Comment> pageN = new Page<>(pageNum,pageSize);
        Page<Comment> page = page(pageN, queryWrapper);
        //封装返回
        List<CommentVo> list = toCommentVoList(page.getRecords());
        return ResponseResult.okResult(new PageVo(list,page.getTotal()));
    }

    //comment 集合 和commentVo 集合的拷贝
    private List<CommentVo> toCommentVoList(List<Comment> list){
        List<CommentVo> commentVos = BeanCopyUtils.copyBeanList(list, CommentVo.class);

        //遍历vo
        for (CommentVo commentVo : commentVos){
            //通过createBy查询用户的昵称并且赋值
            String nickName = userService.getById(commentVo.getCreateBy()).getNickName();
            commentVo.setUsername(nickName);
            //通过 toCommentUserId查询用户ude昵称并赋值
            //如果 toCommentUserId != -1才进行查询
            if (commentVo.getToCommentId() != -1){
                String toCommentName = userService.getById(commentVo.getToCommentId()).getNickName();
                commentVo.setToCommentUserName(toCommentName);
            }
        }
        return commentVos;
    }
}

查询根评论对应的子评论

也就是多条评论

image-20230316122832752
image-20230316122832752
代码语言:javascript
代码运行次数:0
复制
//查询所有根评论对应的子评论的集合 ,并且赋值给对应的属性children
 for (CommentVo commentVo : list){
     //查询对应子评论
     List<CommentVo> children = getChildren(commentVo.getId());
     commentVo.setChildren(children);
 }

service层

代码语言:javascript
代码运行次数:0
复制
/todo 评论列表
@Override
public ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize) {
    //根据文章id 所对应的 根评论(root_id = -1)
    LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
    //对articleId进行判断
    queryWrapper.eq(Comment::getArticleId,articleId);
    queryWrapper.eq(Comment::getRootId, SystemConstants.ARTICLE_ROOT_COMMENT);
    //分页查询
    Page<Comment> pageN = new Page<>(pageNum,pageSize);
    Page<Comment> page = page(pageN, queryWrapper);
    //封装返回
    List<CommentVo> list = toCommentVoList(page.getRecords());
    //查询所有根评论对应的子评论的集合 ,并且赋值给对应的属性children
    for (CommentVo commentVo : list){
        //查询对应子评论
        List<CommentVo> children = getChildren(commentVo.getId());
        commentVo.setChildren(children);
    }
    return ResponseResult.okResult(new PageVo(list,page.getTotal()));
}

//todo 根据根评论的id查询对应的子评论的集合
private List<CommentVo> getChildren(Long commentId){
    LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(Comment::getRootId,commentId);
    List<Comment> list = list(queryWrapper);
    //封装成为CommentVo,然后返回
    return toCommentVoList(list);
}

//comment 集合 和commentVo 集合的拷贝
private List<CommentVo> toCommentVoList(List<Comment> list){
    List<CommentVo> commentVos = BeanCopyUtils.copyBeanList(list, CommentVo.class);

    //遍历vo
    for (CommentVo commentVo : commentVos){
        //通过createBy查询用户的昵称并且赋值
        String nickName = userService.getById(commentVo.getCreateBy()).getNickName();
        commentVo.setUsername(nickName);
        //通过 toCommentUserId查询用户ude昵称并赋值
        //如果 toCommentUserId != -1才进行查询
        if (commentVo.getToCommentId() != -1){
            String toCommentName = userService.getById(commentVo.getToCommentId()).getNickName();
            commentVo.setToCommentUserName(toCommentName);
        }
    }
    return commentVos;
}

发表评论

请求

image-20230316124356854
image-20230316124356854

如果是友链 type为 1

还需要有请求体

实现

代码语言:javascript
代码运行次数:0
复制
package com.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blog.domain.ResponseResult;
import com.blog.domain.entity.Comment;
import com.blog.domain.entity.LoginUser;
import com.blog.domain.entity.User;
import com.blog.domain.vo.CommentVo;
import com.blog.domain.vo.PageVo;
import com.blog.enums.AppHttpCodeEnum;
import com.blog.exception.SystemException;
import com.blog.mapper.CommentMapper;
import com.blog.service.CommentService;
import com.blog.service.UserService;
import com.blog.utils.BeanCopyUtils;
import com.blog.utils.SecurityUtils;
import com.blog.utils.SystemConstants;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.sql.rowset.BaseRowSet;
import java.util.List;
import java.util.Objects;

@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Resource
    private UserService userService;

    //todo 评论列表
    @Override
    public ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize) {
        //根据文章id 所对应的 根评论(root_id = -1)
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        //对articleId进行判断
        queryWrapper.eq(Comment::getArticleId,articleId);
        queryWrapper.eq(Comment::getRootId, SystemConstants.ARTICLE_ROOT_COMMENT);
        //分页查询
        Page<Comment> pageN = new Page<>(pageNum,pageSize);
        Page<Comment> page = page(pageN, queryWrapper);

        //封装返回
        List<CommentVo> list = toCommentVoList(page.getRecords());
        //查询所有根评论对应的子评论的集合 ,并且赋值给对应的属性children
        for (CommentVo commentVo : list){
            //查询对应子评论
            List<CommentVo> children = getChildren(commentVo.getRootId());
            commentVo.setChildren(children);
        }
        return ResponseResult.okResult(new PageVo(list,page.getTotal()));
    }

    //todo 添加评论
    @Override
    public ResponseResult addComment(Comment comment) {
        //评论内容不能为空
        if(!StringUtils.hasText(comment.getContent())){
            throw new SystemException(AppHttpCodeEnum.CONTENT_NOT_NULL);
        }
        save(comment);
        return ResponseResult.okResult();
    }

    //todo 根据根评论的id查询对应的子评论的集合
    private List<CommentVo> getChildren(Long commentId){
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getRootId,commentId);
        queryWrapper.orderByAsc(Comment::getCreateTime);
        List<Comment> list = list(queryWrapper);
        //封装成为CommentVo,然后返回
        return toCommentVoList(list);
    }


    //todo comment 集合 和commentVo 集合的拷贝
    private List<CommentVo> toCommentVoList(List<Comment> list){
        List<CommentVo> commentVos = BeanCopyUtils.copyBeanList(list, CommentVo.class);
        //遍历vo
        for (CommentVo commentVo : commentVos){
            //通过createBy查询用户的昵称并且赋值
            String nickName = userService.getById(commentVo.getCreateBy()).getNickName();
            commentVo.setUsername(nickName);
            //通过 toCommentUserId查询用户ude昵称并赋值
            //如果 toCommentUserId != -1才进行查询
            if (commentVo.getToCommentUserId() != -1){
                String toCommentUserName = userService.getById(commentVo.getToCommentUserId()).getNickName();
                commentVo.setToCommentUserName(toCommentUserName);
            }
        }
        return commentVos;
    }
}

友链评论

接口

image-20230318111815616
image-20230318111815616

实现

代码语言:javascript
代码运行次数:0
复制
@GetMapping("/linkCommentList")
public ResponseResult listCommentList(Integer pageNum , Integer pageSize){
    return commentService.commentList(SystemConstants.COMMENT_TYPE_FRIEND,null,pageNum,pageSize);
}
代码语言:javascript
代码运行次数:0
复制
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Resource
    private UserService userService;

    //todo 评论列表
    @Override
    public ResponseResult commentList(String commentType, Long articleId, Integer pageNum, Integer pageSize) {
        //根据文章id 所对应的 根评论(root_id = -1)
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();

        //对articleId进行判断  ,必须是文章评论再显示这个条件
        queryWrapper.eq(SystemConstants.COMMENT_TYPE_ARTICLE.equals(commentType),Comment::getArticleId,articleId);
        queryWrapper.eq(Comment::getRootId, SystemConstants.ARTICLE_ROOT_COMMENT);
        //评论类型
        queryWrapper.eq(Comment::getType,commentType);
        //分页查询
        Page<Comment> pageN = new Page<>(pageNum,pageSize);
        Page<Comment> page = page(pageN, queryWrapper);

        //封装返回
        List<CommentVo> list = toCommentVoList(page.getRecords());
        //查询所有根评论对应的子评论的集合 ,并且赋值给对应的属性children
        for (CommentVo commentVo : list){
            //查询对应子评论
            List<CommentVo> children = getChildren(commentVo.getRootId());
            commentVo.setChildren(children);
        }
        return ResponseResult.okResult(new PageVo(list,page.getTotal()));
    }
}

个人中心

接口

image-20230318125856965
image-20230318125856965

表分析

image-20230318125957961
image-20230318125957961

实现

代码语言:javascript
代码运行次数:0
复制
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/userInfo")
    public ResponseResult userInfo(){
        return userService.userInfo();
    }
}
代码语言:javascript
代码运行次数:0
复制
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    //todo 用户中心
    @Override
    public ResponseResult userInfo() {
        //获取当前用户
        Long userId = SecurityUtils.getUserId();
        //根据当前用户id查询当前用户
        User user = getById(userId);
        //封装成userInfoVo返回
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class);
        return ResponseResult.okResult(userInfoVo);
    }
}

个人信息curd

头像上传—-使用七牛云
image-20230318132126703
image-20230318132126703

首先上传至web应用服务器 ,然后再从web服务器上传至 oss

接口

上传文件需求 :

更新个人信息需求 :

image-20230318145103396
image-20230318145103396
实现

上传文件

代码语言:javascript
代码运行次数:0
复制
@RestController
public class UploadController {
    @Autowired
    private UploadService uploadService;

    @PostMapping("/upload")
    public ResponseResult uploadImg(MultipartFile img){
        return uploadService.uploadImg(img);
    }
}
代码语言:javascript
代码运行次数:0
复制
/**
 * 上传文件到七牛云
 */
@ConfigurationProperties(prefix = "oss")
@Service
@Data
public class UploadServiceImpl implements UploadService {

    //todo 实现文件的上传
    @Override
    public ResponseResult uploadImg(MultipartFile img) {
        //判断文件的大小
        //获取原始文件名进行判断
        String originalFilename = img.getOriginalFilename();
        if(!originalFilename.endsWith(".png") && !originalFilename.endsWith(".jpg")){
            return ResponseResult.errorResult(AppHttpCodeEnum.FILE_TYPE_ERROR);
        }
        //如果通过,上传文件到oss
        String url = uploadOSS(img);

        return ResponseResult.okResult(url);
    }

    private String accessKey;
    private String secretKey;
    private String bucket;


    private String uploadOSS(MultipartFile imgFile){
        //构造一个带指定 Region 对象的配置类
        Configuration cfg = new Configuration(Region.autoRegion());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //默认不指定key的情况下,以文件内容的hash值作为文件名

        //images目录下的文件
        String originalFilename = imgFile.getOriginalFilename();

        String key = "images/"+originalFilename;
        try {
            //将前端传过来的imgFile文件转换成一个inputStream,然后
            InputStream inputStream = imgFile.getInputStream();
            Auth auth = Auth.create(accessKey, secretKey);
            String upToken = auth.uploadToken(bucket);
            try {
                Response response = uploadManager.put(inputStream,key,upToken,null, null);
                //解析上传成功的结果
                DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
                System.out.println(putRet.key);
                System.out.println(putRet.hash);
            } catch (QiniuException ex) {
                Response r = ex.response;
                System.err.println(r.toString());
                try {
                    System.err.println(r.bodyString());
                } catch (QiniuException ex2) {
                    //ignore
                }
            }
        } catch (Exception ex) {
            //ignore
        }
        //文件地址
        return "http://rrpanx30j.hd-bkt.clouddn.com/images/"+ originalFilename;
    }
}

更新个人信息实现 :

代码语言:javascript
代码运行次数:0
复制
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/userInfo")
    public ResponseResult userInfo(){
        return userService.userInfo();
    }

    @PutMapping("/userInfo")
    public ResponseResult updateUserInfo(@RequestBody User user){
        return userService.updateUserInfo(user);
    }
}
代码语言:javascript
代码运行次数:0
复制
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    //todo 用户中心
    @Override
    public ResponseResult userInfo() {
        //获取当前用户
        Long userId = SecurityUtils.getUserId();
        //根据当前用户id查询当前用户
        User user = getById(userId);
        //封装成userInfoVo返回
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class);
        return ResponseResult.okResult(userInfoVo);
    }


    //todo 更新个人信息
    @Override
    public ResponseResult updateUserInfo(User user) {
        updateById(user);
        return ResponseResult.okResult();
    }
}

登录系统

接口

image-20230313163836015
image-20230313163836015

请求and响应信息

image-20230313163731178
image-20230313163731178

表分析

image-20230313180949226
image-20230313180949226

思路分析

image-20230313181433354
image-20230313181433354

登录

①自定义登录接口

调用ProviderManager的方法进行认证 如果认证成功生成jwt

把信息存入redis中

②自定义UserDetailsServic e

在这个实现类中进行查询数据库操作

注意配置密码加密BCryptPasswordCoder

校验

①自定义jwt认证过滤器

获取token

解析token获取其中的userId

从redis中获取用户信息

存入securityContextHolder

配置信息

代码语言:javascript
代码运行次数:0
复制
<!--SpringSecurity启动器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--redis依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--fastjson依赖-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>
<!--jwt依赖-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
</dependency>

实现

登录校验过滤器代码实现

校验

①自定义jwt认证过滤器

获取token

解析token获取其中的userId

从redis中获取用户信息

存入securityContextHolder

JwtAuthenticationTokenFilter

实现

  1. 重新jwt过滤器
代码语言:javascript
代码运行次数:0
复制
/**
 * jwt过滤器
 *
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisCache redisCache;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        // 获取token
        String token = httpServletRequest.getHeader("token");
        if(!StringUtils.hasText(token)){
            //说明该接口不需要登录,直接放行
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }

        // 解析token获取其中的userId
        Claims claims = null;
        try {
            claims = JwtUtil.parseJWT(token);
        } catch (Exception e) {
            //如果异常, 那么就是token超时或者非法
            e.printStackTrace();
            //返回异常信息
            ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
            WebUtils.renderString(httpServletResponse, JSON.toJSONString(result));
            return;
        }
        String userId = claims.getSubject();
        //从redis中获取用户信息
        LoginUser loginUser = redisCache.getCacheObject(SystemConstants.LOGIN_KEY_PREFIX + userId);
        //如果获取不到
        if(Objects.isNull(loginUser)){
            //提示重新登录
            ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
            WebUtils.renderString(httpServletResponse, JSON.toJSONString(result));
            return;
        }

        //存入securityContextHolder
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}
  1. 将过滤器加入到SecurityConfig的配置文件中
代码语言:javascript
代码运行次数:0
复制
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    /**
     * 密码加密
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }



    //todo 认证
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        HttpSecurity disable = http.csrf().disable();
        System.out.println("----"+disable.toString());
        http
                .authorizeRequests()
                //不通过session获取SecurityContext
                //对于登录接口 ,匿名访问
                .mvcMatchers("/login").anonymous()
//用于测试的接口---友链                
            .antMatchers("/link/getAllLink").authenticated()
                //剩下的都不需要认证即可访问
                .anyRequest().permitAll()
                        .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                ;
        http.logout().disable();
        //允许跨域
        http.cors();
        //将自定义的filter添加到过滤器链中
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

}

认证授权异常处理

未处理的异常

image-20230315092254529
image-20230315092254529

上面这种异常处理的方式不符合项目接口的规范,所以我们需要自定义异常处理

实现的认证失败的接口处理

AuthenticationEntryPoint认证失败处理

代码语言:javascript
代码运行次数:0
复制
/**
 * 认证失败处理
 */
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {


    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        //打印异常信息
        e.printStackTrace();
        //判断异常的类型信息
        ResponseResult result = null;
        if(e instanceof BadCredentialsException){
            result = ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_ERROR.getCode(),e.getMessage());
        }else if (e instanceof InsufficientAuthenticationException){
            result = ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_ERROR);
        }//其他情况
        else{
            result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),"认证失败!!!");
        }
            //响应给前端
        WebUtils.renderString(httpServletResponse, JSON.toJSONString(result));
    }
}

AccessDeniedHandler授权失败处理

代码语言:javascript
代码运行次数:0
复制
/**
 * 授权失败处理
 */
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {


    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        //打印异常信息
        e.printStackTrace();
        ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        //响应给前端
        WebUtils.renderString(httpServletResponse, JSON.toJSONString(result));

    }
}

放入SecurityConfig中

代码语言:javascript
代码运行次数:0
复制
//todo 认证
@Override
protected void configure(HttpSecurity http) throws Exception {
    //配置认证和授权的异常处理器
    http.exceptionHandling()
            .authenticationEntryPoint(authenticationEntryPoint)
            .accessDeniedHandler(accessDeniedHandler);

}

对于controller层出现的异常

比如向如下的异常, 用户登录时没有输入用户名,那么如果我们不在controller层进行拦截 ,他就会进入service层

代码语言:javascript
代码运行次数:0
复制
@PostMapping("/login")
public ResponseResult login(@RequestBody User user){
    if (!StringUtils.hasText(user.getUserName())){
        //提示 要传用户名
        throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME);
    }
    return blogLoginService.login(user);
}

所以我们直接在controller层进行拦截

操作

  1. 自定义异常类
代码语言:javascript
代码运行次数:0
复制
public class SystemException extends RuntimeException{

    private int code;

    private String msg;

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public SystemException(AppHttpCodeEnum httpCodeEnum) {
        super(httpCodeEnum.getMsg());
        this.code = httpCodeEnum.getCode();
        this.msg = httpCodeEnum.getMsg();
    }

}
  1. 配置自定义异常拦截器
代码语言:javascript
代码运行次数:0
复制
/**
 * 定义的controller层异常拦截
 * 对于controller层的异常 ,直接进行拦截返回
 */
//@ControllerAdvice
//@ResponseBody
@RestControllerAdvice
@Slf4j      //使用之后可以直接使用log
public class GlobalExceptionHandler {

    @ExceptionHandler(SystemException.class)
    public ResponseResult systemExceptionHandler(SystemException e){
        //1. 打印异常信息
        log.error("出现了异常!  {}",e);
        //2. 从异常对象中获取提示信息
        //3. 封装返回
        return ResponseResult.errorResult(e.getCode(),e.getMsg());
    }
}

退出登录

接口

需要token

image-20230315101032018
image-20230315101032018

登录时 ,我们将用户的相关信息存入到了redis中 ,同时也包括token

如果想要退出 ,我们只需要删除redis中的用户登录数据即可

实现

代码语言:javascript
代码运行次数:0
复制
@PostMapping("/logout")
public ResponseResult logout(){
    return blogLoginService.logout();
}

service

代码语言:javascript
代码运行次数:0
复制
//todo 退出登录
@Override
public ResponseResult logout() {
    //获取 token 解析获取 userId
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    LoginUser loginUser = (LoginUser) authentication.getPrincipal();
    Long userId = loginUser.getUser().getId();

    redisCache.deleteObject(SystemConstants.LOGIN_KEY_PREFIX + userId);
    return ResponseResult.okResult();
}

注册系统

接口

image-20230318151249833
image-20230318151249833

实现

代码语言:javascript
代码运行次数:0
复制
@PostMapping("register")
public ResponseResult register(@RequestBody User user){
    return userService.register(user);
}

业务层实现

代码语言:javascript
代码运行次数:0
复制
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private PasswordEncoder passwordEncoder;
    //todo 注册用户
    @Override
    public ResponseResult register(User user) {
        //对数据进行非空判断 要求用户名 密码 等都不为空
        if(!StringUtils.hasText(user.getUserName())){
            ResponseResult.errorResult(AppHttpCodeEnum.USERNAME_NOT_NULL);
        }
        if( StringUtils.hasText(user.getPassword())){
            ResponseResult.errorResult(AppHttpCodeEnum.PASSWORD_NOT_NULL);
        }
        if( StringUtils.hasText(user.getEmail())){
            ResponseResult.errorResult(AppHttpCodeEnum.EMAIL_NOT_NULL);
        }
        if( StringUtils.hasText(user.getNickName())){
            ResponseResult.errorResult(AppHttpCodeEnum.NICKNAME_EXIST);
        }
        //判断数据库中是否存在用户
        if(usernameExist(user.getUserName())){
            //用户已经存在
            ResponseResult.errorResult(USERNAME_EXIST);
        }
        if(nickNameExist(user.getNickName())){
            //昵称存在
            ResponseResult.errorResult(NICKNAME_EXIST);
        }
        ///密码加密处理
        String encodePass = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodePass); //设置加密之后的密码
        save(user);
        //返回结果
        return ResponseResult.okResult();
    }


    //todo 判断用户名是否存在
    private boolean usernameExist(String username){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName,username);
        int count = count(queryWrapper);
        if(count >= 1){
            return true;
        }
        return false;
    }
    //todo 判断昵称是否存在
    private boolean nickNameExist(String nickName){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getNickName,nickName);
        int count = count(queryWrapper);
        if(count >= 1){
            return true;
        }
        return false;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • daily- blog项目
    • 快速搭建项目
      • 使用EasyCode快速创建工程
      • 自动生成的代码修改
      • 修改service、dao等层
      • 配置Controller及其注意事项
    • 表的设计分析
    • 通用的响应实体类 和 响应枚举
  • 博客前台
    • 热门文章列表
      • 需求
      • 接口设计
      • 使用VO优化
      • 封装Bean拷贝工具类
    • 分类列表需求
      • 需求
      • 表信息
      • 接口设计
      • 实现
    • 分页查询文章列表
      • 需求
      • 接口设计
      • 实现
    • 文章详情接口
      • 需求
      • 接口信息
      • 实现
    • 友链查询
      • 需求
      • 接口设计
      • 表信息
      • 实现
    • 评论列表
      • 接口
      • 需求
      • 表分析
      • 实现
    • 查询根评论对应的子评论
    • 发表评论
      • 请求
      • 实现
    • 友链评论
      • 接口
      • 实现
    • 个人中心
      • 接口
      • 表分析
      • 实现
      • 个人信息curd
  • 登录系统
    • 接口
    • 请求and响应信息
    • 表分析
    • 思路分析
      • 配置信息
      • 实现
    • 登录校验过滤器代码实现
      • 实现
    • 认证授权异常处理
      • AuthenticationEntryPoint认证失败处理
      • AccessDeniedHandler授权失败处理
      • 放入SecurityConfig中
    • 对于controller层出现的异常
      • 操作
    • 退出登录
      • 接口
      • 实现
  • 注册系统
    • 接口
    • 实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档