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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 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日志并进行多维度分析。
目录
相关文章
|
2月前
|
人工智能 监控 算法
3D-Speaker:阿里通义开源的多模态说话人识别项目,支持说话人识别、语种识别、多模态识别、说话人重叠检测和日志记录
3D-Speaker是阿里巴巴通义实验室推出的多模态说话人识别开源项目,结合声学、语义和视觉信息,提供高精度的说话人识别和语种识别功能。项目包含工业级模型、训练和推理代码,以及大规模多设备、多距离、多方言的数据集,适用于多种应用场景。
454 18
3D-Speaker:阿里通义开源的多模态说话人识别项目,支持说话人识别、语种识别、多模态识别、说话人重叠检测和日志记录
|
2月前
|
Java Maven
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
在Java项目中,启动jar包时遇到“no main manifest attribute”错误,且打包大小明显偏小。常见原因包括:1) Maven配置中跳过主程序打包;2) 缺少Manifest文件或Main-Class属性。解决方案如下:
679 8
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
|
3月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
77 1
|
6月前
|
开发框架 .NET Docker
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
|
6月前
|
数据可视化 Java API
如何在项目中快速引入Logback日志并搭配ELK使用
如何在项目中快速引入Logback日志并搭配ELK使用
|
6月前
|
开发框架 .NET API
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?
292 0
|
6月前
|
监控 程序员 数据库
分享一个 .NET Core Console 项目中应用 NLog 写日志的详细例子
分享一个 .NET Core Console 项目中应用 NLog 写日志的详细例子
|
3月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
954 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
2月前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
12天前
|
存储 SQL 关系型数据库
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log、原理、写入过程;binlog与redolog区别、update语句的执行流程、两阶段提交、主从复制、三种日志的使用场景;查询日志、慢查询日志、错误日志等其他几类日志
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log