admin管理员组

文章数量:1616681

博客项目的整个流程与学习

做的每一个知识点要好好的列出来

做项目 应该怎么样去设想功能

做一个项目的时候
用户故事这个方法去 设想项目功能

设计前端的原型

可以自己在画纸上画雏形
也可以在网上找工具制作 bootstrap等等工具

前端页面

为了可以在移动端上面观看
在首页上了加了这个段代码
<meta name="viewport" content="width=device-with, initial-scale=1.0">
https://www.jianshu/p/9e2fb499a0a5

你看像这样可以自己在css(把它当作自己的工具库 设定好后 在添加)中自己设置一套关于padded的工具

然后一些特别就内敛改属性把 style

关于jq的一些事情

刚刚我在写一个js的时候,发现代码是对的,但就是运行不起,结果网上搜了一搜发现…

导入cdn的时候,jQuery一定要往前放,要不然不行真秀

插件的集成

# Markdown插件的集成

(https://pandao.github.io/editor.md)先去这个网站下载插件
然后导入lib包下的文件(下在的文件中能找到)

然后分别导入css 和 js
<link rel="stylesheet" href="../static/lib/editormd/css/editormd.min.css"> <script src="../static/lib/editormd/editormd.min.js"></script>
还需要导入jquery,但本项目之前已经导入了就没加上了

然后给文本区域加上div并命名id(md-content)
然后再写js

    <!--    初始化markdown编辑器-->
  var testEditor;
    $(function() {
                                             md-content就是之前自己写的id
        testEditor = editormd("md-content", {
            width: "100%",
            height: 640,
            syncScrolling: "single",
            path: "../static/lib/editormd/lib/"
        });
    });

文案的排版

https://github/sofish/typo.css

动画

https://daneden.github.io/animate.css/
animated fadeIn

代码高亮

https://github/PrismjS/prism 轻量级

目录生成

https://tscanlin.github.io/tocbot/

二维码生成

https://davidshimjs.github.io/qrcodejs/
qrcode.js debug用的
qrcode.min.js 深层用的
.tar.gz文件一般用于Linux系统上,而.zip文件一般流行于Windows系统上 2.tar.gz格式的文件比.zip文件要小很多

滑轮滚动

https://github/flesler/jquery.scrollTo

滚动侦测

imakewebthings/waypoints/

异常处理

springboot中自定义404 与 500页面就需要在templates中创建个error包然后再创建404html和500html这样,springboot页面就会自动去找这个页面了

然后也可以自己建错误页面,在error包下建一个errorhtml
然后
写了一个类

private final Logger logger = LoggerFactory.getLogger(this.getClass());//通过这条语句得到日志相关的信息,后面返回信息会用到

@ExceptionHandler(Exception.class)//这个注解就是与上面那个注解配合使用的,括号中是级别 class级别的错误
public ModelAndView exceptionHander(HttpServletRequest request, Exception e){
    logger.error("Request URL : {},Exception : {}",request.getRequestURL(),e);

    ModelAndView mv = new ModelAndView();//就是前端与后端的值的传递
    mv.addObject("url",request.getRequestURL());
    mv.addObject("exception",e);
    mv.setViewName("error/error");
    return mv;
}

}

@ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:

全局异常处理
全局数据绑定
全局数据预处理
灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用,下面分别来看。

全局异常处理
使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可定义方式如下:

@ControllerAdvice
public class MyGlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ModelAndView customException(Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("myerror");
        return mv;
    }
}

日志处理 AOP

package com.crz.blog.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect//证明是切面类的注释
@Component
public class LogAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //这个注解就是与切面注解配合使用的了   切点在哪儿 execution就是说要切什么    com.crz.blog.controller包下的所以类的所以方法的所以参数
    @Pointcut("execution(* com.crz.blog.controller.*.*(..))")
    public void log(){}

    @Before("log()")    //在切点之前要做的事   JoinPoint 是切面的类   可以拿到类的相关信息
    public void doBefore(JoinPoint joinPoint){
        //获取HttpServletRequest
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //这里是往日志保存 用户的url ip 还有使用的那个类的方法 参数
        String url = request.getRequestURI();
        String ip = request.getRemoteAddr();
        String classMethod = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        RequestLog requestLog = new RequestLog(url,ip,classMethod,args);
        logger.info("Request : {}",requestLog);

        logger.info("-------------doBefore");
    }

    @After("log()")
    public void doAfter(){
        logger.info("-------------doAfter");
    }

    //返回的内容
    @AfterReturning(returning = "result",pointcut = "log()")
    public void doAfterReturn(Object result){
        logger.info("Result : {}",result);
    }

    private class RequestLog{
        private String url;
        private String ip;
        private String classMethod;
        private Object[] args;

        public RequestLog(String url, String ip, String classMethod, Object[] args) {
            this.url = url;
            this.ip = ip;
            this.classMethod = classMethod;
            this.args = args;
        }

        @Override
        public String toString() {
            return "{" +
                    "url='" + url + '\'' +
                    ", ip='" + ip + '\'' +
                    ", classMethod='" + classMethod + '\'' +
                    ", args=" + Arrays.toString(args) +
                    '}';
        }
    }



}

页面处理

用thymleaf的fragments来给总体换模板
把页面经常用到的部分放到_fragments类中

在这里插入代码片<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3/1999/xhtml">
<head th:fragment="head">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-with, initial-scale=1.0">
    <title>博客详情</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr/npm/semantic-ui@2.4.2/dist/semantic.min.css">
    <link rel="stylesheet" href="../static/css/typo.css" th:href="@{/css/typo.css}">
    <link rel="stylesheet" href="../static/css/animate.css" th:href="@{/css/animate.css}">
    <link rel="stylesheet" href="../static/css/animatepat.css" th:href="@{/css/animatepat.css}">
    <link rel="stylesheet" href="../static/css/animate.min.css" th:href="@{/css/animate.min.css}">
    <link rel="stylesheet" href="../static/lib/prism/prism.css" th:href="@{/lib/prism/prism.css}">
    <link rel="stylesheet" href="../static/lib/tocbot/tocbot.css" th:href="@{/lib/tocbot/tocbot.css}">
    <link rel="stylesheet" href="../static/css/me.css" th:href="@{/css/me.css}">
</head>
<body>

<nav th:fragment="menu(n)" class="ui inverted attached segment m-padded-tb-mini">
    <div class="ui container">
        <div class="ui inverted secondary stackable menu">
            <h2 class="ui teal header item">Blog</h2>
            <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==1} ? 'active'"><i class=" home icon"></i>首页</a>
            <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==2} ? 'active'"><i class=" idea icon"></i>分类</a>
            <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==3} ? 'active'"><i class=" tags icon"></i>标签</a>
            <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==4} ? 'active'"><i class=" clone icon"></i>归档</a>
            <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==5} ? 'active'"><i class=" info icon"></i>关于我</a>
            <div class="right item">
                <div class="ui icon inverted input m-mobile-hide">
                    <input type="text" placeholder="Search....">
                    <i class="search  link icon"></i>
                </div>
            </div>
        </div>
    </div>
    <a href="#" class="ui menu toggle black icon button m-top-right m-mobile-show">
        <i class=" sidebar icon"></i>
    </a>
</nav>


<!--底部-->
<footer th:fragment="footer" class="ui inverted vertical segment m-padded-tb-massive">
    <div class="ui center aligned container">
        <div class="ui inverted divided stackable grid">
            <div class="three wide column">
                <div class="ui inverted link list">
                    <div class="item">
                        <img src="../static/images/wechart.jpg" th:src="@{/images/wechart.jpg}"  class="ui image rounded" alt="" style="width: 110px">
                    </div>
                </div>
            </div>
            <div class="three wide column">
                <h4 class="ui inverted header m-text-thin m-text-spaced ">最新博客</h4>
                <div class="ui inverted link list">
                    <a href="#" class="item">用户故事(User Story)</a>
                    <a href="#" class="item">用户故事(User Story)</a>
                    <a href="#" class="item">用户故事(User Story)</a>
                </div>
            </div>
            <div class="three wide column">
                <h4 class="ui inverted header m-text-thin m-text-spaced ">联系我</h4>
                <div class="ui inverted link list">
                    <a href="#" class="item">Email:1632521464@qq</a>
                    <a href="#" class="item">QQ:1632521464</a>

                </div>
            </div>
            <div class="seven wide column">
                <h4 class="ui inverted header m-text-thin m-text-spaced ">Jeremy</h4>
                <p class="m-text-thin m-text-spaced m-opacity-mini">这是我的个人博客,我会在这里和大家一起学习编程、编曲、吉他,我会经常分享一些自己的经验,希望可以帮助到大家....</p>
            </div>
        </div>
        <div class="ui inverted section divider "></div>
        <p class="m-text-thin m-text-spaced m-opacity-mini">This is my learning project about bolg and study from bilibili - i will finish it in ten days</p>
    </div>

</footer>

<div th:fragment="script">
    <script src="https://cdn.jsdelivr/npm/jquery@3.2/dist/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr/npm/jquery.scrollto@2.1.3/jquery.scrollTo.min.js"></script>
    <script src="https://cdn.jsdelivr/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script>

    <script src="../static/lib/prism/prism.js" th:src="@{/lib/prism/prism.js}"></script>
    <script src="../static/lib/tocbot/tocbot.js" th:src="@{/lib/tocbot/tocbot.js}"></script>
    <script src="../static/lib/qrcode/qrcode.min.js" th:src="@{/lib/qrcode/qrcode.min.js}"></script>
    <script src="../static/lib/waypoints/jquery.waypoints.min.js" th:src="@{/lib/waypoints/jquery.waypoints.min.js}"></script>
</div>


</body>
</html>

在这个类中,把公用的模板改好
再在head或者footer或者nav或者div中 用thymleaf的格式绑定一下例如

<div th:fragment="script">或者
<footer th:fragment="footer" class="ui inverted vertical segment m-padded-tb-massive">....

然后再其他的html页面 需要用的片段就与其相应的绑定 例如head

<head th:replace="_fragments :: head">


footer
th:replace="_fragments :: footer"

实体类的构建(这边通过先创建实体类,再通过实体类创建表)

Blog类

package com.crz.blog.pojo;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Entity
@Table(name = "t_blog")
public class Blog {

    @Id
    @GeneratedValue
    private Long id;
    private String title;
    private String content;
    private String firstPicture;
    private String flag;
    private Integer views;
    private boolean appreciation;
    private boolean shareStatement;
    private boolean commentabled;
    private boolean published;
    private boolean recommend;
    @Temporal(TemporalType.TIMESTAMP)
    private Date createTime;
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateTime;

    @ManyToOne
    private Type type;

    @ManyToMany(cascade = {CascadeType.PERSIST})
    private List<Tag> tags = new ArrayList<>();

    @ManyToOne
    private User user;

    @OneToMany(mappedBy = "blog")
    private List<Comment> comments = new ArrayList<>();


    public Blog() {
    }

    public Blog(Long id, String title, String content, String firstPicture, String flag, Integer views, boolean appreciation, boolean shareStatement, boolean commentabled, boolean published, boolean recommend, Date createTime, Date updateTime) {
        this.id = id;
        this.title = title;
        this.content = content;
        this.firstPicture = firstPicture;
        this.flag = flag;
        this.views = views;
        this.appreciation = appreciation;
        this.shareStatement = shareStatement;
        thismentabled = commentabled;
        this.published = published;
        this.recommend = recommend;
        this.createTime = createTime;
        this.updateTime = updateTime;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<Comment> getComments() {
        return comments;
    }

    public void setComments(List<Comment> comments) {
        thisments = comments;
    }

    public String getTitle() {
        return title;
    }

    public List<Tag> getTags() {
        return tags;
    }

    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getFirstPicture() {
        return firstPicture;
    }

    public void setFirstPicture(String firstPicture) {
        this.firstPicture = firstPicture;
    }

    public String getFlag() {
        return flag;
    }

    public void setFlag(String flag) {
        this.flag = flag;
    }

    public Integer getViews() {
        return views;
    }

    public void setViews(Integer views) {
        this.views = views;
    }

    public boolean isAppreciation() {
        return appreciation;
    }

    public void setAppreciation(boolean appreciation) {
        this.appreciation = appreciation;
    }

    public boolean isShareStatement() {
        return shareStatement;
    }

    public void setShareStatement(boolean shareStatement) {
        this.shareStatement = shareStatement;
    }

    public boolean isCommentabled() {
        return commentabled;
    }

    public void setCommentabled(boolean commentabled) {
        thismentabled = commentabled;
    }

    public boolean isPublished() {
        return published;
    }

    public void setPublished(boolean published) {
        this.published = published;
    }

    public boolean isRecommend() {
        return recommend;
    }

    public void setRecommend(boolean recommend) {
        this.recommend = recommend;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Blog{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", firstPicture='" + firstPicture + '\'' +
                ", flag='" + flag + '\'' +
                ", views=" + views +
                ", appreciation=" + appreciation +
                ", shareStatement=" + shareStatement +
                ", commentabled=" + commentabled +
                ", published=" + published +
                ", recommend=" + recommend +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                '}';
    }
}

这边用的是JPA与数据库做操作,但我自己还是想用mybatisplus去做持久层

导入依赖

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>

因为这边有一对多,多对一,多对多用到了高级映射了,resultMap ,只靠mybatisplus自带的增删改查是不行的


按着实体类pojo把Mapper层写出来

因为要自己写sql语句了,可以用注释也可以选择xml文件


功能写好了就可以在service层去初步的使用使用了


后台传值给Thymleaf页面

https://blog.csdn/laidanlove250/article/details/93499126

这个项目做的一些登录拦截呀,密码登录加密,session之类的,都是用的最基础,最好是项目做完改一下,把安全框架shiro或者security(?)应用上去

登录拦截


登录拦截一定时预先处理 和 配置相结合使用
LoginInterceptor

package com.crz.blog.aspect.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//之前有个方法过时了
public class LoginInterceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(request.getSession().getAttribute("user") == null){
            response.sendRedirect("/admin");
            return false;
        }
        return true;

    }
}

WebConfig

package com.crz.blog.aspect.interceptor;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("admin/**")
                .excludePathPatterns("/admin")
                .excludePathPatterns(("/admin/login"));
    }
}

来说一下今天下午做的分页插件把,视频用的是JPA自带的,我用的是Mybatisplus的

自己对于这些知识掌握确实太不牢固了,导致就做一个分页插件就花了一下午

package com.crz.blog.MybatisPlusConfig;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.crz.blog.mapper")
public class Mp {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

这是mp的分页插件的配置类,用之前要写好,还有一些细致的配置不是很清楚

在controller层中做的逻辑

    @Autowired
    TypeMapper typeMapper;

    @GetMapping("/types")
    //默认是第一页   currentPage代表了当前的页数,前端来改变这个变量
    public String types(@RequestParam(defaultValue = "1") Integer currentPage, Model model){
//这里就把currentPage和10传入到page中了,分别代表当前页数和分页多少条记录
        Page<Type> page = new Page<>(currentPage, 10);
        //然后再把page传入进去,这边wrapper我还没学,或者说之前学了忘了......
        IPage pageData = typeMapper.selectPage(page, new QueryWrapper<Type>().orderByDesc("id"));
        //然后把page传入到前端去
        model.addAttribute("page",pageData);

        return "admin/types";

    }

pageData的信息分别有
“records”: [
{
“id”: 18,
“userId”: 1,
“title”: “sdsa”,
“description”: “asds”,
“content”: “”,
“created”: “2021-04-24”,
“status”: 0
}
],
“total”: 10,
“size”: 5,
“current”: 1,
“orders”: [

],
“searchCount”: true,
“pages”: 2

然后前端Thymleaf应用

  <table class="ui celled table">
            <thead>
            <tr >
                <th></th>
                <th>名称</th>

                <th>操作</th>
            </tr>
            </thead>

            <tbody>

//这里再表的外层 th:each 用type和iterStat去取里面的信息(上面提到records代表数据)

            <tr th:each="type,iterStat:${page.records}">
               <td th:text="${iterStat.count}">1</td>
                <td th:text="${type.name}">刻意练习清单</td>
                <td>
                    <a href="#" th:href="@{/admin/types/{id}/input(id=${type.id})}"class="ui mini basic teal button">编辑</a>
                    <a href="#" th:href="@{/admin/types/{id}/input(id=${type.id})}"class="ui mini basic red button">删除</a>
                </td>
            </tr>
            </tbody>
            <tfoot>
            <tr>
                <!--                把6列合并在一起-->
                <th colspan="6">
                    <div class="ui  mini pagination menu">
                        <a th:href="@{/admin/types(currentPage=${page.current}-1)}" href="#" class="item">上一页</a>
                        <a th:href="@{/admin/types(currentPage=${page.current}+1)}" class="item">下一页</a>
                    </div>

                    <a href="#" th:href="@{/admin/types/input}"class="ui mini right floated teal basic button">新增</a>

                </th>
            </tr>
            </tfoot>
        </table>

语法:th:each=“obj,iterStat:${objList}”

迭代对象可以是java.util.List,java.util.Map,数组等;

iterStat称作状态变量,属性有:
index:当前迭代对象的index(从0开始计算)
count: 当前迭代对象的index(从1开始计算)
size:被迭代对象的大小
current:当前迭代变量
even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算)
first:布尔值,当前循环是否是第一个
last:布尔值,当前循环是否是最后一个

本文标签: 流程项目