[SpringBoot3]博客管理系统(源码放评论区了)

八、博客管理系统

  • 创建新的SpringBoot项目,综合运用以上知识点,做一个文章管理的后台应用。
  • 依赖:
    • Spring Web
    • Lombok
    • Thymeleaf
    • MyBatis Framework
    • MySQL Driver
    • Bean Validation
    • hutool
  • 需求:文章管理工作,发布新文章,编辑文章,查看文章内容等

8.1配置文件

1.组织配置文件

app-base.yml

article:
  #最低阅读数
  low-read: 10
  #首页显示记录的数量
  top-read: 20

db.properties(一定要用properties)

#配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=030522
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=10
#获取连接时,检测语句
spring.datasource.hikari.connection-test-query=select 1
spring.datasource.hikari.connection-timeout=20000
#其他属性
spring.datasource.hikari.data-source-properties.cachePrepStmts=true
spring.datasource.hikari.data-source-properties.dataSource.cachePrepStmtst=true
spring.datasource.hikari.data-source-properties.dataSource.prepStmtCacheSize=250
spring.datasource.hikari.data-source-properties.dataSource.prepStmtCacheSqlLimit=2048
spring.datasource.hikari.data-source-properties.dataSource.useServerPrepStmts=true

<img src=“C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230902103338099.png” alt="image-20230902103338099" style="zoom:80%;" />

8.2视图文件

2.logo文件

  • favicon.ico 放在 static/ 根目录下

3.创建模板页面

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

articleList.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="icon" th:href="@{/favicon.ico}" type="image/x-icon"/>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<div style="margin-left: 200px">
    <h3>阅读最多的20篇文章</h3>
    <table border="1px" cellpadding="0px" cellspacing="0px">
        <thead>
        <th>选择</th>
        <th>序号</th>
        <th>标题</th>
        <th>副标题</th>
        <th>已读数</th>
        <th>发布时间</th>
        <th>最后修改时间</th>
        <th>操作</th>
        </thead>
        <tbody>
        <tr th:each="article , loopStatus : ${articleList}">
            <td><input type="checkbox" th:value="${article.id}"></td>
            <td th:text="${loopStatus.index + 1}"></td>
            <td th:text="${article.title}"></td>
            <td th:text="${article.summary}"></td>
            <td th:text="${article.readCount}"></td>
            <td th:text="${article.createTime}"></td>
            <td th:text="${article.updateTime}"></td>
            <td><a th:href="@{/article/get(id=${article.id})}">编辑文章</a> </td>
        </tr>
        <tr>
            <td colspan="8">
                <table width="100%">
                    <tr>
                        <td><button id="add" onclick="addArticle()">发布新文章</button></td>
                        <td><button id="del" onclick="deleteArticle()">删除文章</button></td>
                        <td><button id="view" onclick="overView()">文章概览</button></td>
                    </tr>
                </table>
            </td>
        </tr>
        </tbody>
    </table>
    <form id="frm" th:action="@{/view/addArticle}" method="get"></form>

    <form id="delFrm" th:action="@{/article/remove}" method="post">
        <input type="hidden" name="ids" id="ids" value="">
    </form>
</div>
<script>
    function addArticle(){
        $("#frm").submit();
    }
    function deleteArticle(){
        var ids=[];
        $("input[type='checkbox']:checked").each((index,item)=>{
            ids.push(item.value);
        })
        if (ids.length==0){
            alert("请选择文章");
            return;
        }
        $("#ids").val(ids);
        $("#delFrm").submit();
    }
    function overView(){
        var ids = [];
        $("input[type='checkbox']:checked").each( (index,item) =>{
            ids.push(item.value);
        })
        if( ids.length != 1){
            alert("请选择一个文章查看");
            return;
        }
        $.get("../article/detail/overview",{id: ids[0]}, (data,status)=>{
            alert(data);
        })
    }
</script>
</body>
</html>

addArticle.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="icon" th:href="@{/favicon.ico}" type="image/x-icon"/>
</head>
<body>
<div style="margin-left: 200px">
    <h3>发布新的文章</h3>
    <form th:action="@{/article/add}" method="post">
        <table>
            <tr>
                <td>标题</td>
                <td><input type="text" name="title"></td>
            </tr>
            <tr>
                <td>副标题</td>
                <td><input type="text" name="summary" size="50"></td>
            </tr>
            <tr>
                <td>内容</td>
                <td><textarea name="content" cols="60" rows="20"></textarea></td>
            </tr>
        </table>
        <br/>
        <input type="submit" value="发布新文章" style="margin-left: 200px">
    </form>
</div>
</body>
</html>

editArticle.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="icon" th:href="@{/favicon.ico}" type="image/x-icon"/>
</head>
<body>
<div style="margin-left: 200px">
    <h3>修改文章</h3>
    <form th:action="@{/article/edit}" method="post">
        <table>
            <tr>
                <td>标题</td>
                <td><input type="text" name="title" th:value="${article.title}"></td>
            </tr>
            <tr>
                <td>副标题</td>
                <td><input type="text" name="summary" size="50" th:value="${article.summary}"></td>
            </tr>
            <tr>
                <td>内容</td>
                <td><textarea name="content" cols="60" rows="20" th:text="${article.content}"></textarea></td>
            </tr>
        </table>
        <br/>
        <input type="hidden" th:value="${article.id}" name="id">
        <input type="submit" value="确认修改" style="margin-left: 200px">
    </form>
</div>
</body>
</html>

bind.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="icon" th:href="@{/favicon.ico}" type="image/x-icon"/>
</head>
<body>
<h3>输入异常</h3>
<table border="1px">
    <thead>
    <th>字段</th>
    <th>描述</th>
    </thead>
    <tbody>
    <tr th:each="err:${errors}">
        <td th:text="${err.field}"></td>
        <td th:text="${err.defaultMessage}"></td>
    </tr>
    </tbody>
</table>
</body>
</html>

error.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="icon" th:href="@{/favicon.ico}" type="image/x-icon"/>
</head>
<body>
<h3>请求错误</h3>
<h3 th:text="${msg}"></h3>
</body>
</html>

8.3Java代码

4.java代码

model包

ArticleDTO

package com.hhb.blog.model.dto;

import lombok.Data;

@Data
public class ArticleDTO {
    private Integer id;
    private String title;
    private String summary;
    private String content;
}

ArticleAndDetailMap

package com.hhb.blog.model.map;

import lombok.Data;

@Data
public class ArticleAndDetailMap {
    private Integer id;
    private String title;
    private String summary;
    private String content;
}

ArticleParam

package com.hhb.blog.model.param;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class ArticleParam {
    //使用JSR303注解
    public static interface AddArticle{};
    public static interface EditArticle{};

    @NotNull(message = "修改时必须有id",groups = {EditArticle.class})
    @Min(value = 1,message = "文章id大于{value}",groups = {EditArticle.class})
    private Integer id;

    @NotBlank(message = "请输入文章标题",groups = {AddArticle.class,EditArticle.class})
    @Size(min = 2,max = 20,message = "文章标题在{min}-{max}",groups = {AddArticle.class,EditArticle.class})
    private String title;

    @NotBlank(message = "请输入文章副标题",groups = {AddArticle.class,EditArticle.class})
    @Size(min = 10,max=30,message = "文章副标题在{min}-{max}",groups = {AddArticle.class,EditArticle.class})
    private String summary;

    @NotBlank(message = "请输入文章内容",groups = {AddArticle.class,EditArticle.class})
    @Size(min = 20,max = 8000,message = "文章内容至少{min}字,最多{max}字",groups = {AddArticle.class,EditArticle.class})
    private String content;

}

ArticleDeatilPO

package com.hhb.blog.model.po;

import lombok.Data;

@Data
public class ArticleDetailPO {
  private Integer id;
  private Integer articleId;
  private String content;
}

ArticlePO

package com.hhb.blog.model.po;

import lombok.Data;

import java.time.LocalDateTime;

@Data
public class ArticlePO {
  private Integer id;
  private Integer userId;
  private String title;
  private String summary;
  private Integer readCount;
  private LocalDateTime createTime;
  private LocalDateTime updateTime;
}

ArticleVO

package com.hhb.blog.model.po;

import lombok.Data;

import java.time.LocalDateTime;

@Data
public class ArticlePO {
  private Integer id;
  private Integer userId;
  private String title;
  private String summary;
  private Integer readCount;
  private LocalDateTime createTime;
  private LocalDateTime updateTime;
}

mapper包

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ArticleMapper

package com.hhb.blog.mapper;

import com.hhb.blog.model.dto.ArticleDTO;
import com.hhb.blog.model.map.ArticleAndDetailMap;
import com.hhb.blog.model.po.ArticleDetailPO;
import com.hhb.blog.model.po.ArticlePO;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface ArticleMapper {
    //查询首页需要的文章列表
    @Select("""
            select id,user_id ,title,summary, read_count , create_time, update_time
            from article
            where read_count >= #{lowRead}
            order by read_count desc 
            limit #{topRead}
            """)
    List<ArticlePO> topSortByReadCount(Integer lowRead, Integer topRead);

    //添加文章
    @Insert("""
            insert into article(user_id, title, summary, read_count, create_time, update_time)
            values(#{userId},#{title},#{summary},#{readCount},#{createTime},#{updateTime})
            """)
    //主键自增
    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
    int insertArticle(ArticlePO articlePO);

    //添加文章内容
    @Insert("""
            insert into article_detail(article_id, content) 
            values(#{articleId},#{content})
            """)
    int insertArticleDetail(ArticleDetailPO articleDetailPO);

    //两表连接,根据主键查询文章
    @Select("""
            select article.id,title,summary,content
            from article,article_detail
            where article.id=article_detail.article_id and article_id=#{id}
            """)
    ArticleAndDetailMap selectArticleAndDetail(Integer id);

    //修改文章属性
    @Update("""
            update article 
            set title=#{title},summary=#{summary},update_time=#{updateTime}
            where id=#{id}
            """)
    int updateArticle(ArticlePO articlePO);

    //更新文章内容
    @Update("""
            update article_detail set content=#{content} where article_id=#{articleId}
            """)
    int updateArticleDetail(ArticleDetailPO articleDetailPO);

    //删除文章
    @Delete("""
            <script>
              delete from article where id in 
              <foreach item="id" collection="idList" open="(" separator="," close=")">
                  #{id}
              </foreach>
            </script>
            """)
    int deleteArticle(List<Integer> idList);

    //删除文章内容
    @Delete("""
            <script>
              delete from article_detail where article_id in 
              <foreach item="id" collection="idList" open="(" separator="," close=")">
                  #{id}
              </foreach>
            </script>
            """)
    int deleteDetail(List<Integer> idList);

    //根据id查询内容
    @Select("""
      select id,article_id,content from article_detail
      where article_id = #{articleId}
      """)
    ArticleDetailPO selectArticleDetailByArticleId(Integer articleId);
}

service包

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ArticleService

package com.hhb.blog.service;

import com.hhb.blog.model.dto.ArticleDTO;
import com.hhb.blog.model.po.ArticlePO;

import java.util.List;

public interface ArticleService {

    //获取首页文章列表
    List<ArticlePO> queryTopArticle();

    //发布文章(article,article_detail)
    boolean addArticle(ArticleDTO articleDTO);

    //根据主键查询文章
    ArticleDTO queryByArticleId(Integer id);

    //修改文章属性和内容
    boolean modifyArticle(ArticleDTO articleDTO);

    //删除文章
    boolean removeArticle(List<Integer> idList);

    //查询文章内容前20个字符
    String queryTop20Content(Integer id);
}

ArticleServiceImpl

package com.hhb.blog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.hhb.blog.mapper.ArticleMapper;
import com.hhb.blog.model.dto.ArticleDTO;
import com.hhb.blog.model.map.ArticleAndDetailMap;
import com.hhb.blog.model.po.ArticleDetailPO;
import com.hhb.blog.model.po.ArticlePO;
import com.hhb.blog.service.ArticleService;
import com.hhb.blog.settings.ArticleSettings;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Random;

@Service
@RequiredArgsConstructor
public class ArticleServiceImpl implements ArticleService {

    private final ArticleMapper articleMapper;
    private final ArticleSettings articleSettings;

    //构造注入
 /* public ArticleServiceImpl(ArticleMapper articleMapper) {
    this.articleMapper = articleMapper;
  }*/

    @Override
    public List<ArticlePO> queryTopArticle() {
        Integer lowRead = articleSettings.getLowRead();
        Integer topRead = articleSettings.getTopRead();
        return articleMapper.topSortByReadCount(lowRead, topRead);
    }

    //发布文章
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addArticle(ArticleDTO articleDTO) {
        //文章
        ArticlePO articlePO = new ArticlePO();
        articlePO.setTitle(articleDTO.getTitle());
        articlePO.setSummary(articleDTO.getSummary());
        articlePO.setCreateTime(LocalDateTime.now());
        articlePO.setUpdateTime(LocalDateTime.now());
        articlePO.setReadCount(new Random().nextInt(1000));
        articlePO.setUserId(new Random().nextInt(5000));
        int addArticle = articleMapper.insertArticle(articlePO);

        //文章内容
        ArticleDetailPO articleDetailPO = new ArticleDetailPO();
        articleDetailPO.setArticleId(articlePO.getId());
        articleDetailPO.setContent(articleDTO.getContent());
        int addDetail = articleMapper.insertArticleDetail(articleDetailPO);

        return (addDetail + addArticle) == 2 ? true : false;
    }

    @Override
    public ArticleDTO queryByArticleId(Integer id) {
        //文章属性,内容
        ArticleAndDetailMap mapper = articleMapper.selectArticleAndDetail(id);
        //转为DTO,两种方式
        /*ArticleDTO articleDTO = new ArticleDTO();
        articleDTO.setTitle(mapper.getTitle());
        articleDTO.setContent(mapper.getContent());
        articleDTO.setSummary(mapper.getSummary());
        articleDTO.setId(mapper.getId());*/
        ArticleDTO articleDTO = BeanUtil.copyProperties(mapper, ArticleDTO.class);
        return articleDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean modifyArticle(ArticleDTO articleDTO) {
        //修改文章属性
        ArticlePO articlePO = new ArticlePO();
        articlePO.setTitle(articleDTO.getTitle());
        articlePO.setSummary(articleDTO.getSummary());
        articlePO.setUpdateTime(LocalDateTime.now());
        articlePO.setId(articleDTO.getId());
        int article = articleMapper.updateArticle(articlePO);

        //修改文章内容
        ArticleDetailPO articleDetailPO = new ArticleDetailPO();
        articleDetailPO.setArticleId(articleDTO.getId());
        articleDetailPO.setContent(articleDTO.getContent());
        int detail = articleMapper.updateArticleDetail(articleDetailPO);

        return (article + detail) == 2 ? true : false;
    }

    //删除文章属性、内容
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeArticle(List<Integer> idList) {
        int article = articleMapper.deleteArticle(idList);
        int detail = articleMapper.deleteDetail(idList);
        return article == detail ? true : false;
    }

    //查询文章内容前20个字符
    @Override
    public String queryTop20Content(Integer id) {
        ArticleDetailPO articleDetailPO = articleMapper.selectArticleDetailByArticleId(id);
        String content = "无内容";
        if( articleDetailPO != null ){
            content = articleDetailPO.getContent();
            if(StringUtils.hasText(content)){
                //content = content.substring(0, content.length() >= 20 ? 20 : content.length() );
                content = content.substring(0, 20 );
            }
        }
        return content;
    }
}

controller包

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ArticleController

package com.hhb.blog.controller;

import cn.hutool.core.bean.BeanUtil;
import com.hhb.blog.format.IdType;
import com.hhb.blog.handler.exp.IdTypeException;
import com.hhb.blog.model.dto.ArticleDTO;
import com.hhb.blog.model.param.ArticleParam;
import com.hhb.blog.model.po.ArticlePO;
import com.hhb.blog.model.vo.ArticleVO;
import com.hhb.blog.service.ArticleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RequiredArgsConstructor
@Controller
public class ArticleController {

    private final ArticleService articleService;

    @GetMapping(value = {"/", "/article/hot"})
    public String showHotArticle(Model model) {
        List<ArticlePO> articlePOList = articleService.queryTopArticle();
        //转为VO  .hutool工具类
        List<ArticleVO> articleVOList = BeanUtil.copyToList(articlePOList, ArticleVO.class);

        //添加数据
        model.addAttribute("articleList", articleVOList);

        //视图
        return "/blog/articleList";
    }

    //发布新文章
    @PostMapping("/article/add")
    //接收对象类型参数
    public String addArticle(@Validated(ArticleParam.AddArticle.class) ArticleParam param) {
        ArticleDTO articleDTO = new ArticleDTO();
        articleDTO.setContent(param.getContent());
        articleDTO.setSummary(param.getSummary());
        articleDTO.setTitle(param.getTitle());
        boolean add = articleService.addArticle(articleDTO);
        return "redirect:/article/hot";
    }

    //查询文章内容
    @GetMapping("/article/get")
    public String queryById(Integer id, Model model) {
        if (id != null && id > 0) {
            ArticleDTO articleDTO = articleService.queryByArticleId(id);
            //DTO-VO
            ArticleVO articleVO = BeanUtil.copyProperties(articleDTO, ArticleVO.class);
            //添加数据
            model.addAttribute("article", articleVO);
            //视图
            return "/blog/editArticle";
        } else {
            return "/blog/error/error";
        }
    }

    //更新文章
    @PostMapping("/article/edit")
    public String modifyArticle(@Validated(ArticleParam.EditArticle.class) ArticleParam param) {
        /*ArticleDTO articleDTO = new ArticleDTO();
        articleDTO.setId(param.getId());
        articleDTO.setTitle(param.getTitle());
        articleDTO.setSummary(param.getSummary());
        articleDTO.setContent(param.getContent());*/
        ArticleDTO articleDTO = BeanUtil.copyProperties(param, ArticleDTO.class);
        boolean edit = articleService.modifyArticle(articleDTO);
        return "redirect:/article/hot";
    }

    //删除文章
    @PostMapping("/article/remove")
    //public String removeArticle(Integer ids[])
    public String removeArticle(@RequestParam("ids") IdType idType) {
        if (idType == null) {
            throw new IdTypeException("ID为空");
        }
        boolean delete = articleService.removeArticle(idType.getIdList());
        return "redirect:/article/hot";
    }

    //预览文章
    @GetMapping("/article/detail/overview")
    @ResponseBody
    public String queryDetail(Integer id) {
        String top20Content = "无ID";
        if (id != null) {
            top20Content = articleService.queryTop20Content(id);
        }
        return top20Content;
    }
}

异常处理包

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GlobalExceptionHandler

package com.hhb.blog.handler;

import java.util.List;

import com.hhb.blog.handler.exp.IdTypeException;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {
    //处理JSR303
    @ExceptionHandler({BindException.class})
    public String handlerBindException(BindException bindException, Model model) {
        BindingResult bindingResult = bindException.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        model.addAttribute("errors", fieldErrors);
        return "/blog/error/bind";
    }

    @ExceptionHandler({IdTypeException.class})
    public String handleIdTypeException(IdTypeException idTypeException, Model model) {
        model.addAttribute("msg", idTypeException.getMessage());
        return "/blog/error/error";
    }

    @ExceptionHandler({Exception.class})
    public String handleDefaultException(Exception e, Model model) {
        model.addAttribute("msg", "请稍后重试!");
        return "/blog/error/error";
    }
}

BlogRootException

package com.hhb.blog.handler.exp;

public class BlogRootException extends RuntimeException{
    public BlogRootException() {
    }

    public BlogRootException(String message) {
        super(message);
    }
}

IdTypeException

package com.hhb.blog.handler.exp;

public class IdTypeException extends BlogRootException {
    public IdTypeException() {
    }

    public IdTypeException(String message) {
        super(message);
    }
}

数据格式化包

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

IdType

package com.hhb.blog.format;

import lombok.Data;

import java.util.List;

@Data
public class IdType {
    private List<Integer> idList;
}

IdTypeFormatter

package com.hhb.blog.format;

import org.springframework.format.Formatter;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class IdTypeFormatter implements Formatter<IdType> {
    @Override
    public IdType parse(String text, Locale locale) throws ParseException {
        IdType idType = null;
        if (StringUtils.hasText(text)) {
            List<Integer> ids = new ArrayList<>();
            for (String id : text.split(",")) {
                ids.add(Integer.parseInt(id));
            }
            idType = new IdType();
            idType.setIdList(ids);
        }
        return idType;
    }

    @Override
    public String print(IdType object, Locale locale) {
        return null;
    }
}

设置包

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ArticleSettings

package com.hhb.blog.settings;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "article")
public class ArticleSettings {
    private Integer lowRead;
    private Integer topRead;
}

MvcSettings

package com.hhb.blog.settings;

import com.hhb.blog.format.IdTypeFormatter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcSettings implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/view/addArticle").setViewName("/blog/addArticle");
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new IdTypeFormatter());
    }
}

启动类

package com.hhb.blog;

import com.hhb.blog.settings.ArticleSettings;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@MapperScan(basePackages = "com.hhb.blog.mapper")
@EnableConfigurationProperties({ArticleSettings.class})
@SpringBootApplication
public class Springboot20BlogAdminApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot20BlogAdminApplication.class, args);
    }

}

8.4界面展示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ja kar ta

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值