Daily-Blog项目前台日志(上)

简介: Daily-Blog项目前台日志(上)

daily- blog项目



快速搭建项目


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


使用EasyCode快速创建工程


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


image-20230311094114784.png


自动生成的代码修改


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


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


image-20230311101039158.png


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


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

/**
 * 文章表(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就方便很多


public interface ArticleMapper extends BaseMapper<Article> {
}

service层


public interface ArticleService extends IService<Article> {
}

impl实现类上加注解

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
}


配置Controller及其注意事项


Controller层


@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.png


表的设计分析


image-20230311102627224.png


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


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;
    }
}
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.png


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


@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.png



需求


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


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


接口设计


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


controller层


//todo 查询热门文章
@GetMapping("/hotArticleList")
public ResponseResult hotArticleList(){
    //查询热门文章,然后封装成ResponseResult ,然后返回
    return articleService.hotArticleList();
}


service层实现


@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.png

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


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


/**
 * 接口文档中要去响应回去的字段
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HotArticle {
    //文章id
    private Long id;
    //文章标题
    private String title;
    //访问量
    private Long viewCount;
}

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


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拷贝工具类


/**

* 有关拷贝工具类的封装
 * @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.png


需求


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


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


表信息


image-20230311150302648.png


接口设计


image-20230311151015334.png


@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层等的代码实现

@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);
    }
}

注意点: 了解函数式编程



相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
5月前
|
canal 消息中间件 关系型数据库
微服务轮子项目(36) -Canal数据库日志解析消费
微服务轮子项目(36) -Canal数据库日志解析消费
62 0
|
4月前
|
Java Maven
maven 项目配置日志打印以及异常日志打印问题
maven 项目配置日志打印以及异常日志打印问题
59 0
|
4月前
|
SQL Java 数据库连接
SpringBoot项目中Mybatis不打印日志怎么办?
SpringBoot项目中Mybatis不打印日志怎么办?
162 0
|
4月前
|
存储 JSON 数据管理
【云备份|| 日志 day1】项目认识 && 环境准备
【云备份|| 日志 day1】项目认识 && 环境准备
|
5月前
|
JavaScript
如何在egret项目中加入vconsole打印日志
如何在egret项目中加入vconsole打印日志
25 0
|
5月前
|
缓存 Java API
微服务轮子项目(38) -分布式日志链路跟踪
微服务轮子项目(38) -分布式日志链路跟踪
73 0
|
5月前
|
SQL 关系型数据库 MySQL
微服务轮子项目(15) -审计日志
微服务轮子项目(15) -审计日志
47 0
|
25天前
|
Java
使用Java代码打印log日志
使用Java代码打印log日志
81 1
|
26天前
|
Linux Shell
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
78 1
|
30天前
|
SQL 关系型数据库 MySQL
MySQL数据库,可以使用二进制日志(binary log)进行时间点恢复
对于MySQL数据库,可以使用二进制日志(binary log)进行时间点恢复。二进制日志是MySQL中记录所有数据库更改操作的日志文件。要进行时间点恢复,您需要执行以下步骤: 1. 确保MySQL配置文件中启用了二进制日志功能。在配置文件(通常是my.cnf或my.ini)中找到以下行,并确保没有被注释掉: Copy code log_bin = /path/to/binary/log/file 2. 在需要进行恢复的时间点之前创建一个数据库备份。这将作为恢复的基准。 3. 找到您要恢复到的时间点的二进制日志文件和位置。可以通过执行以下命令来查看当前的二进制日志文件和位
100 1