Daily-Blog项目后台日志(中)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Daily-Blog项目后台日志(中)


后台项目改进点


关于项目中实现后台模块中的各个菜单及其子菜单的实现


1.首先查询对应用户的菜单


/**
   * 根据用户id查询相关的权限菜单信息
   * @param userId 用户id
   * @return 返回符合要求的val
   */
  @Override
  public List<Menu> selectRouterMenuTreeByUserId(Long userId) {
      MenuMapper menuMapper = getBaseMapper();
      List<Menu> menus = null;    //封装Menu
      //如果是管理员,返回所有的菜单
      if(SecurityUtils.isAdmin()){
          menus = menuMapper.selectAllRouterMenu();
      }
      else{
          //如果不是管理员 那么返回对应有权限的菜单按钮
          menus = menuMapper.selectRouterMenuTreeByUserId(userId);
      }
      //通过上述得到的Menu无法得到我们需要的父子菜单管理,所以我们需要通过(buildMenuTree)来构建这种父子菜单关系
      //构建Tree
      //先找出第一层的菜单,接着找到他们的子菜单,然后就可以设置children属性中
      List<Menu> menuTree = buildMenuTree(menus,0L);
      return menuTree;
  }

2.接着对于那些第一级菜单进行查询(parentId == 1)


/**
 * 构建菜单的父子菜单关系
 * <br>
 * 找到父menu对应的子menu ,然后将他们放到一个集合中,最后设置给children这个字段
 * @param menus 传入的方法
 * @param parentId 父菜单id
 * @return
 */
private List<Menu> buildMenuTree(List<Menu> menus, Long parentId) {
    //用常规的方法
    List<Menu> test = new ArrayList<>();
    for(Menu menu : menus){
        //查询出那些 父菜单的id为 【 1】 的 ,也就是第一级菜单
        if(menu.getParentId().equals(parentId)){
            //获取这些菜单的子菜单
            Menu menu1 = menu.setChildren(getChildren(menu, menus));
            test.add(menu1);
        }
    }
    return test;
}

3.查询对应的子菜单


/**
 * 获取传入参数的子menu的list集合
 *  在menus中找打当前传入的menu的子菜单
 * @param menu 获取它的子菜单
 * @param menus 全部菜单集合
 */
private List<Menu> getChildren(Menu menu, List<Menu> menus){
    List<Menu> test1 = new ArrayList<>();
    for (Menu menu1 : menus){
        if(menu1.getParentId().equals(menu.getId())){
            test1.add(menu1);
        }
    }
    return test1;
}


改进

在上述我们的代码中,如果仅仅是实现两层菜单还可以满足, 但是如果出现菜单层级是3 、4、5…等情况我上述实现的代码就无法满足。


这是我们就需要使用到递归算法 但是这里如果单单使用递归好像很难实现


所以我们在这里可以使用函数式编程,然后在其中套用递归来实现


/**
 * 构建菜单的父子菜单关系
 * <br>
 * 找到父menu对应的子menu ,然后将他们放到一个集合中,最后设置给children这个字段
 * @param menus 传入的方法
 * @param parentId 父菜单id
 * @return
 */
private List<Menu> buildMenuTree(List<Menu> menus, Long parentId) {
    List<Menu> menuList = menus.stream()//通过这样筛选就可以得到第一层级的menu
            .filter(menu -> menu.getParentId().equals(parentId))
            /*
            传入的menus是得到了第一层的menus(相当于Tree中的root节点),然后需要设置他的子菜单(left 和 right)
            因为menus中有所有的菜单(父子都有), 所以我们在设置left和right时需要找到他们的子菜单
            所以就调用getChildren找到left或者right的子菜单,然后得到之后再设置给他们
             */
            .map(menu -> menu.setChildren(getChildren(menu, menus)))
            .collect(Collectors.toList());
    return menuList;
}


/**
 * 获取传入参数的子menu的list集合
 *  在menus中找打当前传入的menu的子菜单
 * @param menu 获取它的子菜单
 * @param menus 全部菜单集合
 */
private List<Menu> getChildren(Menu menu, List<Menu> menus){
    List<Menu> children = menus.stream()
            .filter(menu1 -> menu1.getParentId().equals(menu.getId()))
            .map(menu1 -> menu1.setChildren(getChildren(menu1,menus)))  //如果有很多的子菜单,那么就可以用到这个递归
            .collect(Collectors.toList());
    return children;
}

通过这样的该进,我们就可以实现多层菜单的查询


查询标签列表


接口


image-20230324170257378.png

需求 :


提供标签功能,一个文章可以有多个标签。


在后台需要分页查询标签功能,要求能够根据签名进行分页查询。后期可以增加备注查询等需求


注意 :不要把删除了的标签查询出来

image-20230324172918379.png



实现


/**
 * 标签请求
 */
@RestController
@RequestMapping("/content/tag")
public class TagController {
    @Resource
    private TagService tagService;
    /**
     *提供标签功能,一个文章可以有多个标签。
     *
     * 在后台需要分页查询标签功能,要求能够根据签名进行分页查询。**后期可以增加备注查询等需求**
     *
     * 注意 :不要把删除了的标签查询出来
     * @param pageNum 第几页
     * @param pageSize 分页大小
//     * @param name 标签名
//     * @param remark 备注
     * @return
     */
    @GetMapping("/list")
    public ResponseResult<PageVo> list(int pageNum, int pageSize, TagListDto tagListDto){
        return tagService.pageTagList(pageNum,pageSize,tagListDto);
    }
}

service层实现



/**
 * 标签表服务接口
 * @author ray2310
 */
@Service("tagService")
public class TagServiceImpl extends ServiceImpl<TagMapper, Tag> implements TagService {
    //实现分页tag列表
    @Override
    public ResponseResult<PageVo> pageTagList(Integer pageNum, Integer pageSize, TagListDto tagListDto) {
        //分页查询
        Page<Tag> page = new Page<>();
        page.setCurrent(pageNum);
        page.setSize(pageSize);
        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        //如果他们有值 ,那么就会调用这个方法, 如果没有就不会调用
        wrapper.eq(StringUtils.hasText(tagListDto.getName()),Tag::getName,tagListDto.getName());
        wrapper.eq(StringUtils.hasText(tagListDto.getRemark()),Tag::getRemark,tagListDto.getRemark());
        page(page,wrapper);
        PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
        //封装数据返回
        return ResponseResult.okResult(pageVo);
    }
}


新增标签


接口

image-20230326051807981.png


实现


//TODO 新增标签, 测试时需要在数据库记录中有创建时间、更新时间、创建人、创建人字段
@PostMapping
public ResponseResult addTag(@RequestBody TagListDto tagListDto){
    return tagService.addTag(tagListDto);
}

serivce层


//todo 新增标签需求   需要在数据库记录中有创建时间、更新时间、创建人、创建人字段
@Override
public ResponseResult addTag(TagListDto tagListDto) {
    //1. 接收请求信息,判断信息是否为空
    if(ObjectUtils.isEmpty(tagListDto)){
        return ResponseResult.errorResult(AppHttpCodeEnum.TAG_ERROR);
    }
    //2. 获取标签创建者 、获取创建时间
    Long userId = SecurityUtils.getUserId();
    //3. 将的到的信息转换为tag 存储到数据库中
    Tag tag  = new Tag();
    tag.setName(tagListDto.getName());
    tag.setRemark(tagListDto.getRemark());
    tag.setCreateBy(userId);
    save(tag);
    return ResponseResult.okResult(tag);
}


删除标签


接口image-20230326054428595.png



实现


@DeleteMapping("/{id}")
public ResponseResult deleteTag(@PathVariable Long id){
    return tagService.deleteTag(id);
}

service层


//todo 删除标签需求 需要设置逻辑删除 也就是
//`del_flag` int DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)',
@Override
public ResponseResult deleteTag(Long id) {
    //1. 从数据库中查找要删除的id
    //2. 修改其中的delFlag = 1
    //返回删除信息
    UpdateWrapper<Tag> updateWrapper = new UpdateWrapper<>();
    updateWrapper.eq("id",id);
    updateWrapper.set("del_flag",1);
    update(updateWrapper);
    return ResponseResult.okResult();
}


修改标签


接口

1.先获取接口信息image-20230326062601718.png


2.修改接口

image-20230326063414438.png


实现

首先获取指定id的标签


@GetMapping("/{id}")
public ResponseResult getTagById(@PathVariable Long id){
    return tagService.getTagById(id);
}


//todo 获取需要修改的标签信息
@Override
public ResponseResult getTagById(Long id) {
    Tag tag = getById(id);
    TagDto dto = BeanCopyUtils.copyBean(tag, TagDto.class);
    return ResponseResult.okResult(dto);
}

修改获取的内容


@PutMapping
public ResponseResult updateTag(@RequestBody TagDto tagDto){
    return tagService.updateTag(tagDto);
}


//todo 修改信息
@Override
public ResponseResult updateTag(TagDto tagDto) {
    System.out.println(tagDto.toString());
    UpdateWrapper<Tag> updateWrapper = new UpdateWrapper<>();
    updateWrapper.eq("id",tagDto.getId());
    updateWrapper.set("name",tagDto.getName());
    updateWrapper.set("remark",tagDto.getRemark());
    update(updateWrapper);
    return ResponseResult.okResult();
}


写文章


接口

首先获取所有的分类信息接口image-20230326070053043.png


获取所有的标签请求接口

image-20230326070053043.png


上传图片接口

image-20230326070301832.png


写博文接口


image-20230326070423388.png

实现

首先获取所有的分类信息接口

//todo 获取所有分类信息
@GetMapping("/category/listAllCategory")
public ResponseResult listAllCategory(){
    return categoryService.listAllCategory();
}


@Override
public ResponseResult listAllCategory() {
    //查询出所有没有删除的分类
    LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(Category::getStatus, SystemConstants.CATEGORY_STATUS);//没有被禁用的
    queryWrapper.eq(Category::getDelFlag,SystemConstants.CATEGORY_NOTDEL);//没有被删除的
    List<Category> list = list(queryWrapper);
    List<CategoryVo> categoryVo1s = BeanCopyUtils.copyBeanList(list, CategoryVo.class);
    return ResponseResult.okResult(categoryVo1s);
}

获取所有的标签信息


//todo 获取所有的标签信息
@GetMapping("/tag/listAllTag")
public ResponseResult listAllTag(){
    return tagService.listAllTag();
}


//todo 获取所有的标签,不分页的
@Override
public ResponseResult listAllTag() {
    //查询出所有没有删除的标签
    LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(Tag::getDelFlag, SystemConstants.TAG_NOTDEL);
    List<Tag> list = list(queryWrapper);
    List<TagVo> tagVos = BeanCopyUtils.copyBeanList(list, TagVo.class);
    return ResponseResult.okResult(tagVos);
}

上传图片接口


@RestController
public class UploadController {
    @Autowired
    private UploadService uploadService;
    @PostMapping("/upload")
    public ResponseResult uploadImg(MultipartFile img){
        return uploadService.uploadImg(img);
    }
}
package com.blog.service.impl;
import com.blog.domain.ResponseResult;
import com.blog.enums.AppHttpCodeEnum;
import com.blog.service.UploadService;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileInputStream;
import java.io.InputStream;
/**
 * 上传文件到七牛云
 */
@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;
    }
}


写文章实现


@PostMapping("/article")
public ResponseResult writeArticle(@RequestBody ArticleVo articleVo){
    return articleService.writeArticle(articleVo);
}


//todo 后台写文章详情
@Override
@Transactional  //添加事务
public ResponseResult writeArticle(ArticleVo articleVo) {
    Article article = BeanCopyUtils.copyBean(articleVo, Article.class);
    save(article);
    //将标签id的集合存入标签文章集合表中
    List<ArticleTag> collect = articleVo.getTags().stream().map(tagId -> new ArticleTag(article.getId(), tagId)).collect(Collectors.toList());
    articleTagService.saveBatch(collect);
   return ResponseResult.okResult();
}


修改文章


需求 :点击修改文章时能够跳转回到写博文页面


回显该文章的全部信息


用户可以在该页面进行修改博文信息,点击更新后可以实现修改文章


接口

根据id获取博文

image-20230328201801346.pngimage-20230328201812622.png


修改博文

image-20230328205243997.png


实现

按文章id查询文章回显数据


//todo 获取要更新的博文
@GetMapping("/{id}")
public ResponseResult updateBefore(@PathVariable Long id){
    return articleService.updateBefore(id);
}
/**
 * 后台更新博文前获取博文所有信息
 * @param id 文章id
 * @return 返回所有信息
 */
@Override
public ResponseResult updateBefore(Long id) {
    //1. 首先根据id获取所有信息
    AdminArticleVo articleVo = BeanCopyUtils.copyBean(getById(id), AdminArticleVo.class);
    //2. 获取所有的标签id,然后找出我们需要的
    List<Long> ids = articleTagService.selectByArticleId(id);
    articleVo.setTags(ids);
    //2. 根据文章id 获取其所有的标签tags
    System.out.println(articleVo);
    //3. 封装返回
    return ResponseResult.okResult(articleVo);
}

修改更新


//todo 更新文章
@PutMapping
public ResponseResult updateNow(@RequestBody AdminArticleVo articleVo){
    return articleService.updateNow(articleVo);
}


/**
     * 首先更新请求
     * @param articleVo 需要更新的文章
     * @return
     */
    @Override
    public ResponseResult updateNow(AdminArticleVo articleVo) {
       // UpdateWrapper<Article> wrapper = new UpdateWrapper<>();
       // wrapper.eq("id",articleVo.getId());
        Article article = BeanCopyUtils.copyBean(articleVo, Article.class);
//        wrapper.set("id",articleVo.getId());
//        wrapper.set("title",articleVo.getTitle());
//        wrapper.set("content",articleVo.getContent());
//        wrapper.set("summary",articleVo.getSummary());
//        wrapper.set("category_id",articleVo.getCategoryId());
//        wrapper.set("thumbnail",articleVo.getThumbnail());
//        wrapper.set("is_top",articleVo.getIsTop());
//        wrapper.set("status",articleVo.getStatus());
//        wrapper.set("view_count",articleVo.getViewCount());
//        wrapper.set("is_comment",articleVo.getIsComment());
//        wrapper.set("update_by",articleVo.getUpdateBy());
//        wrapper.set("update_time",articleVo.getUpdateTime());
//        update(wrapper);
        updateById(article);
        //先删除对应的映射关系
        articleTagService.deleteByArticleId(articleVo.getId(),articleVo.getTags());
        //然后重新添加新增的标签映射关系
        List<ArticleTag> collect = articleVo.getTags().stream().map(tagId -> new ArticleTag(article.getId(), tagId)).collect(Collectors.toList());
        articleTagService.saveBatch(collect);
        return ResponseResult.okResult();
    }


@Service
public class ArticleTagServiceImpl extends ServiceImpl<ArticleTagMapper, ArticleTag> implements ArticleTagService {
    @Override
    public List<Long> selectByArticleId(Long id){
        List<ArticleTag> list = list();
        List<Long> ids = new ArrayList<>();
        for(ArticleTag articleTag : list){
            if(articleTag.getArticleId().equals(id)){
                Long tagId = articleTag.getTagId();
                ids.add(tagId);
            }
        }
        return ids;
    }
    @Override
    public void deleteByArticleId(Long id,List<Long> ids){
        LambdaQueryWrapper<ArticleTag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ArticleTag::getArticleId,id);
        remove(wrapper);
    }
}


删除文章


需求 ,删除文章是指逻辑删除,而不是真的删除


接口image-20230328214440779.png



实现


@DeleteMapping("/{id}")
public ResponseResult deleteArticleById(@PathVariable Long id){
    return articleService.deleteArticleById(id);
}
/**
 * 根据id逻辑删除文章
 * @param id 文章id
 * @return 删除结果
 */
@Override
public ResponseResult deleteArticleById(Long id) {
    UpdateWrapper<Article> wrapper = new UpdateWrapper<>();
    wrapper.eq("id",id);
    wrapper.set("del_flag",SystemConstants.DELETE);
    update(wrapper);
    return ResponseResult.okResult();
}


文章列表


接口

image-20230326081110657.pngimage-20230326081713597.png



实现


@GetMapping("/article/list")
public ResponseResult articleList(int pageNum, int pageSize, ArticleSummaryDto articleSummary){
    return articleService.getAllArticle(pageNum,pageSize,articleSummary);
}


//todo 后台博文获取所有博文
@Override
public ResponseResult getAllArticle(int pageNum, int pageSize, ArticleSummaryDto articleSummary) {
    LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
    //如果有categoryId ,那么查询和传入的就需要相同
    //状态 : 正式发布
    queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_PUT);
    //置顶的文章(对isTop进行排序)
    //分页查询
    Page<Article> pageN = new Page<>(pageNum,pageSize);
    Page<Article> page = page(pageN, queryWrapper);
    //查询categoryName ,因为我们封装的是categoryName,但是查询出来的确实categoryId,所以需要在进行查询
    List<Article> articles = page.getRecords();
    List<AdminArticleVo> articleVos = BeanCopyUtils.copyBeanList(articles, AdminArticleVo.class);
    PageVo pageVo = new PageVo(articleVos, page.getTotal());
    return ResponseResult.okResult(pageVo);
}


导出Excel文件


需求 : 将我们需要的文件 ,比如标签信息等导出成为一个Excel文件


接口

image-20230327170559042.png


实现


@GetMapping("/export")
public void exportExcel(HttpServletResponse response){
    //1. 设置下载文件的请求头
    try {
        WebUtils.setDownLoadHeader("分类.xlsx",response);
        List<CategoryVo> list = categoryService.listAllCategory();
        //2. 获取导出的数据
        //3. 把数据写道Excel
        List<ExcelCategoryVo> excelCategoryVos = BeanCopyUtils.copyBeanList(list, ExcelCategoryVo.class);
        EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出")
                .doWrite(excelCategoryVos);
        //4. 如果出现异常响应json格式
    } catch (Exception e) {
        ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR);
        WebUtils.renderString(response, JSON.toJSONString(result));
    }
}


权限控制


只针对有权限的用户访问能够访问的信息


操作

1.在springSecurity中添加


@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

2.在需要访问的方法上加

image-20230327185502326.png


3.封装权限到loginUser中


package com.blog.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.blog.domain.entity.LoginUser;
import com.blog.domain.entity.User;
import com.blog.mapper.MenuMapper;
import com.blog.mapper.UserMapper;
import com.blog.utils.SystemConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private MenuMapper menuMapper;
    @Resource
    private UserMapper userMapper;
    /**
     * 使用该方法来重写用户登录的校验工作
     * @param username 传入username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名查询数据库用户信息
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName,username);
        User user = userMapper.selectOne(queryWrapper);
        //判断是否查询到  : 未查到抛出异常   : 查到然后作比较
        if(Objects.isNull(user)){
            throw new RuntimeException("用户不存在!!!");
        }
        /**
         * 还需要做的 : 后台用户查询权限信息封装
         *
         */
        //用户是管理员
        if(user.getType().equals(SystemConstants.ADMIN)){
            //查询用户权限集合
            List<String> perms = menuMapper.selectPermsByUserId(user.getId());
            //封装到loginUser
            return new LoginUser(user,perms);
        }
        //返回用户信息
        return new LoginUser(user,null);
    }
}


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
7天前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
25 1
|
3月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
125 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
3月前
|
开发框架 .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中的问题
|
3月前
|
XML Java Maven
logback在springBoot项目中的使用 springboot中使用日志进行持久化保存日志信息
这篇文章详细介绍了如何在Spring Boot项目中使用logback进行日志记录,包括Maven依赖配置、logback配置文件的编写,以及实现的日志持久化和控制台输出效果。
logback在springBoot项目中的使用 springboot中使用日志进行持久化保存日志信息
|
3月前
|
数据可视化 Java API
如何在项目中快速引入Logback日志并搭配ELK使用
如何在项目中快速引入Logback日志并搭配ELK使用
|
3月前
|
开发框架 .NET API
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?
150 0
|
3月前
|
监控 程序员 数据库
分享一个 .NET Core Console 项目中应用 NLog 写日志的详细例子
分享一个 .NET Core Console 项目中应用 NLog 写日志的详细例子
|
2天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
64 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
29天前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
176 3
|
29天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1607 14