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:布尔值,当前循环是否是最后一个
版权声明:本文标题:一个项目的流程 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1728741544a1171122.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论