当前位置: 首页 > news >正文

武汉网站优化怎么做/整合营销

武汉网站优化怎么做,整合营销,咸阳万企网站建设,小马网站建设文章目录博客系统前端代码 :1. add.html2. blog_detail.html3. blog_edit.html4. blog_list.html5. login.htmlcss 文件1. blog_detail.css2. blog_edit.css3. blog_list.css4. common.css5. login.css6. 分页器使用的 css后端代码1.config 包1.1 AppConfig类1.2 Lo…

文章目录

  • 博客系统
    • 前端代码 :
      • 1. add.html
      • 2. blog_detail.html
      • 3. blog_edit.html
      • 4. blog_list.html
      • 5. login.html
    • css 文件
      • 1. blog_detail.css
      • 2. blog_edit.css
      • 3. blog_list.css
      • 4. common.css
      • 5. login.css
      • 6. 分页器使用的 css
    • 后端代码
      • 1.config 包
        • 1.1 AppConfig类
        • 1.2 LoginIntercept 类
        • 1.3 MyExceptionAdvice 类
        • 1.4 MyResponseAdvice 类
      • 2. controller 包
        • 2.1 UserController 类
        • 2.2 BlogController类
      • 3. mapper 包
        • 3.1 UserMapper 接口
        • 3.2 BlogMapper 接口
      • 4. model 包
        • 4.1 User类
        • 4.2 Blog 类
      • 5. service 包
        • 5.1 UserService 类
        • 5.2 BlogService 类
      • 6. util 包
        • 6.1 Constant 类</font>
        • 6.2 PasswordUtil类
        • 6.3 ResponseBodyMessage 类
      • 7. Mybatis 包
        • 7.1 UserMapper.xml
        • 7.2 BlogMapper.xml

博客系统

前端代码 :

1. add.html

<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head><!-- 指定字符集 --><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>添加用户</title><link href="./css/bootstrap.min.css" rel="stylesheet"><script src="./js/jquery.js"></script><script src="./js/common.js"></script><style>body {background-image: url("./imgs/阳台.png");background-repeat: no-repeat;background-size: cover;}#image {width: 400px;height: 250px;border: 1px solid #eee;}.message {width: 110px;height: 50px;line-height: 50px;font-weight: 600;}</style>
</head>
<body><form enctype="multipart/form-data" id="form1"><div class="container" style="width: 400px;"><h3 style="text-align: center;">添加用户</h3><div class="form-group"><label for="username">姓名:</label><input type="text" class="form-control" id="username" name="name" placeholder="请输入姓名"/></div><div class="form-group"><label for="password">密码:</label><input type="password" class="form-control" id="password" name="password" placeholder="请输入密码 "/></div><div class="form-group"><label for="password2">确认密码:</label><input type="password2" class="form-control" id="password2" name="password" placeholder="请输入密码"/></div><div class="form-group"><label>性别:</label><input id="man" type="radio" name="sex" value="" checked="checked"/>&nbsp;&nbsp;&nbsp;<input id="women" type="radio" name="sex" value=""/></div><div class="form-group"><label for="address">籍贯:</label><select name="address" id="address" class="form-control"><option value="">可以不选择</option><option value="北京">北京</option><option value="上海">上海</option><option value="广州">广州</option><option value="深圳">深圳</option><option value="成都">成都</option><option value="杭州">杭州</option><option value="重庆">重庆</option><option value="西安">西安</option><option value="武汉">武汉</option><option value="沧州">沧州</option><option value="江西">江西</option></select></div><div class="form-group"><label for="qq">QQ:</label><input type="text" id="qq" class="form-control" name="qq" placeholder="请输入QQ号码 (非必填) "/></div><div class="form-group"><input type="file" name="filename" id="imgFile"><span class="message">图片样式: </span><img src="" id="image"/></div><div class="form-group" style="text-align: center"><input id="btn_sub" class="btn btn-primary" type="button" value="提交"/><input id="btn_back" class="btn btn-default" type="button" value="返回" onclick="location.href='list.html'"/></div></div></form><!--//   拿到 input  type 为 radio 中的内容 即 获取 男 女let sex = $('input[name=sex]:checked').val();let address = $("#address").val();
--><script>let imgFile = document.querySelector("#imgFile");// 这一部分 : 当我们上传图片后 , 我们的 图片样式 就会将图片显示出来imgFile.onchange = function () {let img = document.querySelector("#image");let image = imgFile.files[0];// let formData = new FormData();if (image) {// formData.append('filename', image);img.src = window.URL.createObjectURL(image);}}// 当点击 提交按钮后 构造数据 , 通过 ajax 发送请求给后端let submit = document.querySelector("#btn_sub");submit.onclick = function () {let username = document.querySelector("#username");let password = document.querySelector("#password");let password2 = document.querySelector("#password2");// 通过 jquery 拿到  性别框里面的内容let sex = jQuery('input[name=sex]:checked').val();let address = document.querySelector('#address').value;let qq = document.querySelector("#qq").value;// jQuery.trim 去掉 前后空格if (jQuery.trim(username.value) === '') {alert("请先输入用户名!!")// 将焦点设置到 id 为 username 的输入 框上username.focus();return false;}if (jQuery.trim(password.value) === '') {alert("请先输入密码");password.focus();return false;}if (jQuery.trim(password2.value)  === '') {alert("请输入确认密码");password2.focus();}if (password.value !== password2.value) {alert("两次密码不同,请重新输入")password.focus();return false;}// 使用 formData 类来返回 jQuery("#form1")[0]let formData = new FormData();formData.append('username', username.value);formData.append('password', password.value);formData.append('qq', qq);formData.append('sex', sex);formData.append('address', address);let img = document.querySelector("#image");let image = imgFile.files[0];if (img.src === '') {console.log('未上传图片 !!! ');formData.append('filename', null);} else {formData.append('filename', image)}jQuery.ajax({type: "POST",url: "/user/add",data: formData,processData: false,contentType: false,success: function (result) {if (result != null && result.data.status > 0) {alert('注册成功!');location.href = "login.html";}else {alert('注册失败')}},error : function(){alert("出错了, 请稍后再试!!!")}})}</script></body>
</html>

2. blog_detail.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>博客详情页</title><link rel="stylesheet" href="./css/common.css"><link rel="stylesheet" href="./css/blog_detail.css"><script src="./js/jquery.js"></script><!--    引入 editor.md 的依赖--><link rel="stylesheet" href="./editor.md/css/editormd.min.css"><script src="./editor.md/lib/marked.min.js"></script><script src="./editor.md/lib/prettify.min.js"></script><script src="./editor.md/editormd.min.js"></script></head>
<body><!-- 导航栏 -->
<div class="nav"><img src="./imgs/阳台.png"><span class="title">我的博客系统</span><!--    这个标签仅仅用于占位 ,把下面几个a 标签挤到右边--><div class="spacer"></div><a href="blog_list.html">主页</a><a href="blog_edit.html">写博客</a><a href="#" id = "remove">注销</a>
</div><!-- 页面主体部分 -->
<div class="container"><!--    左侧信息--><div class="container-left"><!--        使用 这个 .card 表示用户信息--><div class="card"><img src="./imgs/girl.png" alt="图片显示失败"><!--            用户名--><h3></h3><a href="#">Gitee 地址</a><div class='counter'><span>文章</span><span>分类</span></div><div class="counter"><span>1</span><span>2</span></div></div></div><!--    右侧信息--><div class="container-right"><!-- 博客标题 --><h3 class="title" id="title">我的第一篇博客</h3><!-- 博客发布时间--><div class="date">2023-03-02</div><!-- 博客正文 --><div id="content"><!--            <P>--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--            </P>--><!--            <P>--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--            </P>--><!--            <P>--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--                从今天开始我要认真敲代码--><!--            </P>--></div></div></div><script>function getBlogDetail() {jQuery.ajax({type: "GET",// location.search 就是 ?blogId=xurl: "/blog/getblog" + location.search,success: function (result) {if (result != null && result.data.status > 0) {let data = result.data.data;// 1. 构造博客标题let title = document.querySelector("#title");title.innerHTML = data.title;// 2. 构造发布时间let dateDiv = document.querySelector(".date");dateDiv.innerHTML = data.postTime;// 3. 构造正文部分// let content = document.querySelector(".content");//// content.innerHTML = data.content;// 使用 editormd.md 自带的方法 对内容进行渲染editormd.markdownToHTML('content', {markdown: data.content})let userid = data.userid;jQuery.ajax({type: "GET",url: "/user/getuserbyid",data: {"userid": userid,},success: function (result) {if (result != null && result.data.status > 0) {let data = result.data.data;// 通过子类选择器选中 img 元素let img = document.querySelector(".card>img");img.src = "product/" + data.user.url;let title = document.querySelector(".card>h3");title.innerHTML = data.user.username;let spanArr = document.querySelectorAll(".counter>span")spanArr[2].innerHTML = data.blogNumber;spanArr[3].innerHTML = data.type;} else {alert("设置错误!!!")}},error: function () {alert("出错了,请稍后再试!!")}})}}})}getBlogDetail();function getLoginUser() {jQuery.ajax({type: "GET",url: "/user/getuser",success: function (result) {if (result != null && result.data.status > 0) {let img = document.querySelector(".nav>img");img.src = "product/" + result.data.data.url;}}})}getLoginUser();</script><script src="./js/common.js"></script></body>
</html>

3. blog_edit.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>博客编辑页</title><link rel="stylesheet" href="./css/common.css"><link rel="stylesheet" href="./css/blog_edit.css"><script src="./js/jquery.js"></script><!--    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script>--><!--    引入 editor.md 的依赖--><link rel="stylesheet" href="./editor.md/css/editormd.min.css"><script src="./editor.md/lib/marked.min.js"></script><script src="./editor.md/lib/prettify.min.js"></script><script src="./editor.md/editormd.min.js"></script></head>
<body><!-- 导航栏 -->
<div class="nav"><img src="./imgs/阳台.png"><span class="title">我的博客系统</span><!--    这个标签仅仅用于占位 ,把下面几个a 标签挤到右边--><div class="spacer"></div><a href="blog_list.html">主页</a><a href="blog_edit.html">写博客</a><a href="#" id = "remove">注销</a>
</div><!-- 编辑区的容器 -->
<div class="blog-edit-container"><!--    博客标题编译去--><div class="title"><input type="text" id="title" placeholder="请输入文章标题"><input type="text" id="typeid" placeholder="请输入文章类型"><button id="submit">发布文章</button></div><!--    博客编译器,这里用 id 是为了和 markdown 对接--><div id="editor"><!-- 通过 textare 可以设置 editor.md,让编辑器把 markdown 内容也同步的保存到这个隐藏的 textare 中 --><textarea name="content" style="display: none" id="content"></textarea></div><script><!--        初始化编译器-->let editor = editormd("editor", {// 这里的尺寸必须在这试着 ,设置样式会被 editormd 自动覆盖width: "100%",// 设置编译器高度height: "calc(100% - 50px)",// 编译器中的初始内容markdown: "# 在这里写一篇博客",// 指定 editor.md 依赖的插件路径path: "./editor.md/lib/",saveHTMLToTextarea: true})let sumit = document.querySelector("#submit");sumit.onclick = function addBlog() {let title = document.querySelector("#title");let type = document.querySelector("#typeid");let content = document.querySelector("#content");if (title.value.trim() === '') {alert("请输入文章标题!!!")return;}if (type.value.trim() === '') {alert("请输入文章类型 !!!")return;}jQuery.ajax({type: "POST",url: "/blog/add",data: {// trim() 去掉 前后的空格 , 这里 去掉 标题和类型的前后空格"title": title.value.trim(),"type": type.value.trim(),"content": content.value},success: function (result) {if (result != null && result.data.status > 0) {// 此时上传 成功location.href = "blog_list.html";}else {alert("上传失败,请稍后再试!!!")}}})}</script><script src="./js/common.js"></script></div>
</body>
</html>

4. blog_list.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>博客列表页</title><link rel="stylesheet" href="./css/common.css"><link rel="stylesheet" href="./css/blog_list.css"><script src="./js/jquery.js"></script><link href="css/bootstrap.min.css" rel="stylesheet"></head>
<body><!-- 导航栏 -->
<div class="nav"><img src="./imgs/阳台.png" id="image1"><span class="title">我的博客系统</span><!--    这个标签仅仅用于占位 ,把下面几个a 标签挤到右边--><div class="spacer"></div><a href="blog_list.html">主页</a><a href="blog_edit.html">写博客</a><a href="#" id = "remove">注销</a>
</div><!-- 页面主体部分 -->
<div class="container"><!--    左侧信息--><div class="container-left"><!--        使用 这个 .card 表示用户信息--><div class="card"><img src="./imgs/girl.png" alt="图片显示失败" id="image2"><!--            用户名--><h3 id="username"></h3><a href="#">Gitee 地址</a><div class='counter'><span>文章</span><span>分类</span></div><div class="counter"><span id="number1">1</span><span id="number2">2</span></div></div></div><!--    右侧信息--><div class="container-right"><!--        &lt;!&ndash;--><!--            表示一篇博客--><!--        &ndash;&gt;--><!--        <div class="blog">--><!--            &lt;!&ndash;--><!--                   博客标题--><!--            &ndash;&gt;--><!--            <div class="title">我的第一篇博客</div>--><!--            &lt;!&ndash;--><!--                发布时间--><!--            &ndash;&gt;--><!--            <div class="data">--><!--                2023-03-02--><!--            </div>--><!--            &lt;!&ndash;--><!--                博客的摘要--><!--            &ndash;&gt;--><!--            <div class="desc">--><!--                从今天起 , 我要认真敲代码--><!--                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint eaque facilis perferendis! Numquam--><!--                neque voluptatum ab vero expedita possimus fuga eos, illo sapiente delectus quidem natus maiores,--><!--                ipsum impedit rerum?--><!--            </div>--><!--            &lt;!&ndash;--><!--                查看全文按钮--><!--            &ndash;&gt;--><!--            <a href="#">查看全文 &gt;&gt;</a>--><!--        </div>--><div id="page"><nav aria-label="Page navigation"><ul id="all" class="pagination"><li class="active"><a href="javascript:firstPage();">首页</a></li><li><a href="javascript:beforePage();">上一页</a></li><li><a href="javascript:nextPage();">下一页</a></li><li><a href="javascript:lastPage();">末页</a></li><span id="pageinfo" style="font-size: 20px;margin-left: 10px;"></span></ul></nav></div></div>
</div><script>// 这个 ajax 获取登录状态 :jQuery.ajax({type: "GET",url: "/user/getuser",success: function (result) {if (result != null && result.data.status > 0) {let image = document.querySelector("#image1");image.src = "product/" + result.data.data.url;let image2 = document.querySelector("#image2");image2.src = "product/" + result.data.data.url;// 将用户名 换上去let username = document.querySelector("#username");username.innerHTML = result.data.data.username;}}})// 这个 ajax 获取 分类jQuery.ajax({type: "GET",url: "/blog/gettype",success: function (result) {if (result != null && result.data.status > 0) {let number1 = document.querySelector("#number1");let number2 = document.querySelector("#number2");number1.innerHTML = result.data.data[0]number2.innerHTML = result.data.data[1];} else {alert("分类设置失败 !!! ")}},error: function () {alert("出错了, 请稍后再试!!!")}})//  分页功能 :// 1. 当前的页码let pIndex = 1;// 2. 每页显示多少篇博客let pSize = 2;// 3. 总页数let totalPage = 0;// 4. 总条数 (当前所有的博客数目)let totalCount = 0;// 通过 ajax 获取 总页数 和 总条数function getList() {jQuery.ajax({type: "GET",url: "/blog/listbypage",data: {"pIndex": pIndex,"pSize": pSize},success: function (result) {if (result != null && result.data.status > 0) {// 总博客数totalCount = result.data.data.count;// ceil 四舍五入并返回大于等于给定数字的最小整数。totalPage = Math.ceil(parseInt(totalCount) / pSize);let size = result.data.data.list.length;// rightDiv  后面创建的 元素需要挂载 rightDiv 上let rightDiv = document.querySelector(".container-right");for (let i = 0; i < size; i++) {let ret = result.data.data.list[i];let blogDiv = document.createElement('div');// 引入 class 属性blogDiv.className = "blog";// 1. 构造标题let titleDiv = document.createElement('div');titleDiv.innerHTML = ret.title;titleDiv.className = "title";// 将 titleDiv 挂到 blogDiv上blogDiv.appendChild(titleDiv);// 2. 构造 发布时间let dataDiv = document.createElement('div');dataDiv.innerHTML = ret.postTime;dataDiv.className = "data";blogDiv.appendChild(dataDiv);// 3. 构造 文章描述let descDiv = document.createElement('div');descDiv.innerHTML = ret.content;descDiv.className = "desc";blogDiv.appendChild(descDiv);// 4. 构造 查看全文按钮let a = document.createElement('a');a.innerHTML = "查看全文 &gt;&gt;";// 重点 : 这里我们点击查看全文 跳转到 博客详情页 ,这里可以 在 url 里面添加一个 博客id ,// 后面在 博客详情页就可以通过这个 blogId 获取到文章.a.href = "blog_detail.html?blogId=" + ret.blogId;blogDiv.appendChild(a);rightDiv.appendChild(blogDiv);}let page = document.querySelector("#page");rightDiv.appendChild(page);let pageinfo = document.querySelector("#pageinfo");pageinfo.innerHTML = "总共 " + totalCount +" 篇博客" + ",当前是第" + pIndex +"页"pageinfo.style.color =" rgb(32,211,71)";} else {alert("获取失败!!!")}},error: function () {alert("出错了,请稍后在尝试!!!")}})}// getList();// 首页function firstPage() {location.href = "blog_list.html?pIndex=1"}// 上一页function beforePage() {if (pIndex > 1) {pIndex = parseInt(pIndex) - 1;location.href = "blog_list.html?pIndex=" + pIndex;} else {alert("已经是首页了!!!")}}// 下一页function nextPage() {if (pIndex < totalPage) {pIndex = parseInt(pIndex) + 1;location.href = "blog_list.html?pIndex=" + pIndex;} else {alert("已经是末页了!!!")}}// 末页function lastPage() {location.href = "blog_list.html?pIndex=" + totalPage;}// 使用这个 方法来初始话页面function initPage() {// 获取 当前页面的 查询字符串  比如 :?pIndex=2let url = location.search;if (url != '') {// 将 问好 去掉 此时就剩下了 pIndex=2 (假设页数是2)url = url.substring(1);// let kvs = url.split("&");let kvs = url.split("=");pIndex = kvs[1];}getList();}initPage();</script>
<script src="./js/common.js"></script></body>
</html>

5. login.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录页面</title><link rel="stylesheet" href="./css/common.css"><link rel="stylesheet" href="./css/login.css"><script src="./js/jquery.js"></script>
</head>
<body><!-- 导航栏 -->
<div class="nav"><img src="./imgs/阳台.png"><span class="title">我的博客系统</span><!--    这个标签仅仅用于占位 ,把下面几个a 标签挤到右边--><div class="spacer"></div><a href="blog_list.html">主页</a><a href="blog_edit.html">写博客</a>
</div><!--正文部分这个 login-container 是贯穿整个页面的容器
-->
<div class="login-container"><!-- 垂直水平居中的登录对话框    --><div class="login-dialog"><h3>登录</h3><div class="row"><span>用户名</span><input type="text" id="username" placeholder="输入用户名"></div><div class="row"><span>密码</span><input type="password" id="password" placeholder="输入密码"></div><div class="row"><button id="submit">提交</button></div><div class="row"><a id="insert" href = "add.html">注册</a></div><div class="a">没有账户? 点击上面进行注册</div></div></div><script>// 通过 id 选中输入框 ,let username = document.querySelector("#username");// 通过 id 选中密码框let password = document.querySelector("#password");let submit = document.querySelector("#submit");// 点击按钮后触发submit.onclick = function () {// 1. 判断 username or passwordif (jQuery.trim(username.value) === '') {alert("请先输入用户名");}if (jQuery.trim(password.value) === '') {alert("请先输入密码")}// 此时 用户 和密码 都有了 ,发送 请求$.ajax({url: "/user/login",type: "POST",data: {"username": username.value,"password": password.value},// 回调函数success: function (result) {if (result != null && result.data.status > 0) {// 登录成功 , 跳转到 博客列表页location.href = "blog_list.html";} else {//登录 登录失败 ,alert("登录失败,请重新输入")}}})}</script></body>
</html>

css 文件

1. blog_detail.css

/*这个样式文件给博客详情页使用
*//*设置标题样式
*/.container-right .title {/*文字居中*/text-align: center;/*边距 : 距离产生美*/padding: 30px}/*设置日期样式
*/.container-right .date {/*文字颜色*/color: rgb(15, 189, 114);/*位子居中*/text-align: center;/*设置内边距 (下) 为 20px*/padding-bottom: 20px;
}/*设置 段落
*/.container-right .content p {/*缩进 两字符*/text-indent: 2em;/*内边距*/padding: 10px 30px;
}

2. blog_edit.css

/*这个文件用来写博客编辑页的样式
*/.blog-edit-container {width: 1000px;height: calc(100% - 50px);/*外边距*/margin: 0 auto;
}.blog-edit-container .title {height: 50px;/*开启弹性布局*/display: flex;/*垂直居中*/align-items: center;/*中间空白环绕 左右两边没有*/justify-content: space-between;
}#title {height: 40px;width: 595px;/*去掉边框*/border: none;/*文字大小*/font-size: 22px;/*圆角边框*/border-radius: 5px;/*设置左内边距*/padding-left: 5px;/*去掉轮廓线 , 鼠标点击后的黑圈*/outline: none;/*设置背景半透明*/background-color: rgb(255, 255, 255, 0.7);}/*focus : 获取焦点后执行 (相当于鼠标点中 , 背景颜色改为下面)失去焦点 , 回复成原来的样子.
*/
#title:focus {background-color: rgb(255, 255, 255);
}#submit {height: 40px;width: 100px;color: white;background-color: orange;/*去掉边框*/border: none;/*圆角矩形*/border-radius: 10px;
}#submit:active {background-color: skyblue;
}#editor {/*圆角矩形*/border-radius: 15px;/*background-color: rgba(255,255,255,0.8);*//*设置半透明*/opacity: 75%;
}#typeid{height: 40px;width: 285px;/*去掉边框*/border: none;/*文字大小*/font-size: 22px;/*圆角边框*/border-radius: 5px;/*设置左内边距*/padding-left: 5px;/*去掉轮廓线 , 鼠标点击后的黑圈*/outline: none;/*设置背景半透明*/background-color: rgb(255, 255, 255, 0.7);}#typeid:focus {background-color: rgb(255, 255, 255);
}

3. blog_list.css

/*这个文件是给博客列表页实现样式的
*//*设置整个博客的容器元素样式
*/.blog {width: 100%;/*设置边距 : 此时 上下左右都有 20px*/padding: 20px;
}/*设置标题 :
*/
.blog .title {/*设置文字居中*/text-align: center;/*设置字体大小*/font-size: 24px;/*设置粗细*/font-weight: 700;/*设置内边距*/padding: 10px
}/*设置日期 :
*/.blog .data {/*文本居中*/text-align: center;/*设置颜色*/color: rgb(15, 189, 114);/*设置内边距*/padding: 10px
}/*设置摘要
*/.blog .desc {/*设置缩进 2 个汉字*/text-indent: 2em;
}/*设置 查看全文
*/
.blog a {/*a 标签不方便设置样式 , 转为块级元素*/display: block;width: 120px;height: 40px;/*设置上边距*/margin-top: 20px;/*设置水平居中 : 通过margin-left 和 margin-right 来设置*/margin-left: auto;margin-right: auto;/*设置边框*/border: 2px solid black;/*让文字水平居中*/text-align: center;/*让文字垂直居中*/line-height: 40px;/*去掉下划线*/text-decoration: none;/*文字颜色*/color: black;/*背景颜色*/background-color: orange;transition: all 0.8s;border-radius: 10px;
}/*鼠标滑倒按钮上有一些变化
*/
.blog a:hover {color: white;background: skyblue;
}

4. common.css

/* 写样式的起手式 , 先取出浏览器的公共样式 ,并且设置 border-box , 避免元素盒子被内边距和边距撑大 */* {margin: 0;padding: 0;box-sizing: border-box;
}/* 并集选择器 */
html, body {/*html 是页面的最顶成元素 ,高度 100% 是相对父元素来说高度是 100% (和父元素一样高)对于 html 标签来说 , 父元素就是浏览器窗口 , 浏览器多高 , html 就多高body 的父亲是 html ,设为 100% 意思是 body 和 html 一样高此时 body 和 html 的高度都是和浏览器窗口一样高的如果不设置高度 ,此时 元素的默认高度取决于内部的内容*/height: 100%;
}body {background-image: url("../imgs/abc.jpg");/* 拒绝平铺 */background-repeat: no-repeat;/* 尽可能扩展 */background-size: cover;/* 水平垂直居中 */background-position: center center;
}/* 实现导航栏样式 */.nav {/*设置 宽度和父元素一样宽块级元素来说 , 默认就是 width : 100%*/width: 100%;/*这里的高度可以自己调整*/height: 50px;background-color: rgba(51, 51, 51, 0.4);color: white;/*导航栏里面的元素都是水平排列, 弹性布局来设置*/display: flex;/*垂直方向子元素居中 :*/align-items: center;
}.nav img {width: 40px;height: 40px;/*    左侧外边距 */margin-left: 30px;margin-right: 10px;/* 设置圆角矩形 : 把内切圆设置为宽度的一般,就正好是一个圆形 */border-radius: 50%;}.nav a {color: white;/*    去掉下划线 */text-decoration: none;margin: 0 10px;
}.nav .spacer {width: 70%}/*编写页面主体样式
*/.container {/*    设置主体部分宽度 1000px*/width: 1000px;/*高度能够填冲满整个页面 (这里需要减去导航栏的高度)*/height: calc(100% - 50px);/* 水平居中 */margin: 0 auto;/*background-color: red;*//*    弹性布局*/display: flex;/* 垂直居中  */align-items: center;/* 中间使用空白分开 */justify-content: space-between;}.container-left {/*尺寸写百分数, 是相对父元素为基准container-left 的父元素 是 containercontainer 高度已经是 设置好了 ,所以这里的 100%也是设置好了的*/height: 100%;width: 200px;/*    方便观察 加上一个背景色*//*    background-color: black;*/
}.container-right {/*与上面同理*/height: 100%;/*container 设置的总宽度是 1000pxcontainer-left 设置的宽度是 200px这里原本是设置 800px ,但是 需要 一点空隙所以设置为 795px*/width: 795px;/*background-color: green;*//*添加背景颜色*/background-color: rgba(255, 255, 255, 0.8);/*圆角矩形*/border-radius: 10px;/*让这个元素自己能带上滚动条这个属性表示 ,内容没有溢出 ,无滚动条,如果内容一处了,则自动加上滚动条*/overflow: auto;}/*左侧用户信息
*/.card {/*背景颜色  带透明*/background-color: rgba(255, 255, 255, 0.8);/*圆角矩形*/border-radius: 10px;padding: 30px;}/*用户头像
*/
.card img {width: 140px;height: 140px;/*内间距  , 让 内容与边框之间有一点距离*/border-radius: 50%;}/*用户名字
*/
.card h3 {/*让文字水平居中*/text-align: center;/*让文字上下都由边距使用内边距或者外边距均可, 但更倾向使用内边距因为 外边距有时候有坑*/padding: 10px;
}/*用户的 Gitee 链接
*/.card a {/*水平居中*/text-align: center;color: #777;text-decoration: none;/*为了配合上述样式 , 将a 标签设置为块级样式*/display: block;padding: 10px;}.card .counter {/*为了让里面的元素水平排列 , 使用弹性布局*/display: flex;/*每个元素左右两边都有等间距的空白*/justify-content: space-around;/*设置内边距*/padding: 5px;}

5. login.css

/*这个文件专门放登录页面的样式
*/.login-container {/**/width: 100%;/*这里的高度与之前同理 ,需要去掉导航栏的高度*/height: calc(100% - 50px);/*暂时设置一个 背景颜色 方便观察效果*//*background-color: rgb(128, 0, 0);*//*开启弹性布局 (为了让对话框能够 垂直水平居中 使用弹性布局)*/display: flex;/*水平居中*/justify-content: center;/*垂直居中*/align-items: center;}.login-dialog {width: 400px;height: 380px;/*background-color: rgb(0, 180, 0);*/background-color: rgba(255, 255, 255, 0.8);border-radius: 10px;}/*标题
*/
.login-dialog h3 {/*文字居中*/text-align: center;/*设置 内边距 : 上下 为 50px 左右为 0*/padding: 50px 0;
}.login-dialog .row {height: 50px;/*开启弹性布局*/display: flex;/*水平居中*/justify-content: center;/*垂直居中*/align-items: center;
}.login-dialog .row span {width: 100px;font-size: 22px
}/*id 选择器  , 并集选择器
*/
#username, #password {width: 200px;height: 40px;/*圆角矩形*/border-radius: 10px;/*去掉边框*/border: none;/*放大输入框内的字体*/font-size: 18px;/*内边距 : 输入框内文字与边框的内边距*/padding-left: 5px;
}#submit {width: 300px;height: 40px;color: white;background-color: greenyellow;/*去除边框*/border: none;/*圆角矩形*/border-radius: 10px;}/*伪类选择器 让鼠标点击有效果
*/#submit:active {background-color: skyblue;
}#insert {width: 300px;height: 40px;color: white;background-color: greenyellow;/*去除边框*/border: none;/*圆角矩形*/border-radius: 10px;/**垂直居中*/align-items: center;justify-content: center;display: flex;/*使用 下面两个也能是 文字居中*//*text-align: center;*//*line-height: 40px;*//**去掉 a 标签下划线*/text-decoration: none;
}#insert:active {background-color: skyblue;}.login-dialog .a {text-align: left;padding-left: 47px;color: #777777;padding-top: 12px;
}

6. 分页器使用的 css


这里分页器使用的 css 可以去我们的资源里下载 , 这里比较多 ,不放上来了 .

后端代码

1.config 包

1.1 AppConfig类

package com.example.blog_ssm.config;import com.example.blog_ssm.util.PasswordUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AppConfig implements WebMvcConfigurer {// 1. 注入拦截器@Autowiredprivate LoginIntercept loginIntercept;@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/product/**").addResourceLocations("file:D:/ret/");}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginIntercept).addPathPatterns("/**").excludePathPatterns("/user/login").excludePathPatterns("/user/add").excludePathPatterns("/css/**").excludePathPatterns("/js/**").excludePathPatterns("/imgs/**").excludePathPatterns("/login.html").excludePathPatterns("/add.html").excludePathPatterns("/product/**");}@Beanpublic PasswordUtil passwordUtil() {return new PasswordUtil();}
}

1.2 LoginIntercept 类

package com.example.blog_ssm.config;import com.example.blog_ssm.util.Constant;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定义拦截器*/@Component
public class LoginIntercept implements HandlerInterceptor {/*** true  表示已经登录 ,会继续访问目标方法* false  表示未登录 , 跳转到登录页面*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// false : 如果 没有 session 也不会创建HttpSession session = request.getSession(false);if (session != null && session.getAttribute(Constant.USERINFO_SESSION_KEY) != null) {// 表示登录成功return true;}// 403 当前你没有资格访问response.setStatus(403);// 重定向response.sendRedirect("/login.html");return false;}
}

1.3 MyExceptionAdvice 类

package com.example.blog_ssm.config;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap;/*** 统一异常的拦截处理类*/@RestControllerAdvice// 使用 @ControllerAdvice 需要再加一个注解 @ResponseBody (返回一个非静态页面)public class MyExceptionAdvice {@ExceptionHandler(Exception.class)public Object exceptionAdvice(Exception e) {HashMap<String, Object> result = new HashMap<>();result.put("status", -1);result.put("message", "程序异常 : " + e.getMessage());result.put("data", "");return result;}
}

1.4 MyResponseAdvice 类

package com.example.blog_ssm.config;import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.util.HashMap;/*** 返回统一的数据格式* 1. 表示当前的类为 : ControllerAdvice* 2. 实现一个 ResponseBodyAdvice 接口*/@ControllerAdvice
public class MyResponseAdvice implements ResponseBodyAdvice {/*** 是否需要对返回的数据进行重写*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {// false 不重写// ture 重写return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {HashMap<String, Object> result = new HashMap<>();result.put("state", 1);result.put("message", "");result.put("data", body);return result;}
}

2. controller 包

2.1 UserController 类

package com.example.blog_ssm.controller;import com.example.blog_ssm.model.Blog;
import com.example.blog_ssm.model.User;
import com.example.blog_ssm.service.BlogService;
import com.example.blog_ssm.util.Constant;
import com.example.blog_ssm.util.ResponseBodyMessage;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;@RestController
@RequestMapping(value = "/blog")
public class BlogController {@Autowiredprivate BlogService blogService;@RequestMapping(value = "/gettype")public ResponseBodyMessage<List<Integer>> getType(HttpServletRequest request) {List<Integer> list = new ArrayList<>();HttpSession session = request.getSession(false);User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);int ret1 = blogService.getTextNumber(user.getId());int ret2 = blogService.getType(user.getId());list.add(ret1);list.add(ret2);return new ResponseBodyMessage<>(1, "成功", list);}@RequestMapping(value = "/listbypage")public ResponseBodyMessage<HashMap<String, Object>> getListByPage(Integer pIndex, Integer pSize) {HashMap<String, Object> result = new HashMap<>();// 这里 limit 就相当于 pSize// 计算处 offset 从第几个下标 返回 , 当前页码为 0  pIndex - 1 就为 0 乘上我们的 规定一页显示的 5 (pSize)// 等于 0 , 也就是说从 0 下标开始 算 5 个 ,  页码为 1 通过这个公式 能得到从 5 下标开始if (pIndex == null || pSize == null) {return new ResponseBodyMessage<>(-1, "请传入 页码 或 页数", null);}if (pIndex - 1 == -1) {pIndex = 0;} else {pIndex -= 1;}int offset = pIndex * pSize;List<Blog> list = blogService.getListByPage(pSize, offset);if (list == null) {return new ResponseBodyMessage<>(-1, "获取失败", null);}Integer count = blogService.getTextCount();if (count == 0) {return new ResponseBodyMessage<>(-1, "获取失败", null);}for (int i = 0; i < list.size(); i++) {Blog blog = list.get(i);String content = blog.getContent();if (content.length() > 50) {content = content.substring(0, 50) + ".....";}blog.setContent(content);}result.put("list", list);result.put("count", count);return new ResponseBodyMessage<>(1, "获取成功", result);}@RequestMapping(value = "/getblog")public ResponseBodyMessage<Blog> getBlog(Integer blogId) {if (blogId <= 0) {return new ResponseBodyMessage<>(-1, "查询失败,博客id 有误", null);}Blog blog = blogService.getBlogById(blogId);if (blog == null) {return new ResponseBodyMessage<>(-1, "无当前博客", null);}return new ResponseBodyMessage<>(1, "查询成功", blog);}@RequestMapping(value = "add")public ResponseBodyMessage<Boolean> addBlog(String title, String type, String content,HttpServletRequest request) {// 1. 获取 useridHttpSession session = request.getSession(false);User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);Integer ret = blogService.addBlog(user.getId(), title,  content , type);if (ret != 0) {return new ResponseBodyMessage<>(1, "增加成功", true);}return new ResponseBodyMessage<>(-1, "增加失败", false);}}

2.2 BlogController类

package com.example.blog_ssm.controller;import cn.hutool.core.util.IdUtil;
import com.example.blog_ssm.model.Blog;
import com.example.blog_ssm.model.User;
import com.example.blog_ssm.service.BlogService;
import com.example.blog_ssm.service.UserService;
import com.example.blog_ssm.util.Constant;
import com.example.blog_ssm.util.PasswordUtil;
import com.example.blog_ssm.util.ResponseBodyMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;@RestController
@RequestMapping(value = "/user")
public class UserController {@Autowiredprivate UserService userService;// 注入 加密工具类@Autowiredprivate PasswordUtil passwordUtil;@Autowiredprivate BlogService blogService;@Value("${image.local.path}")private String IMAGE_PATH;// 1. 登录功能@RequestMapping(value = "/login")public ResponseBodyMessage<Boolean> login(String username, String password, HttpServletRequest request) {// 1. 判断 用户名和密码 是否为空if (!StringUtils.hasLength(username) && !StringUtils.hasLength(password)) {return new ResponseBodyMessage<>(-1, "登录失败, 用户或密码不能空", false);}// 2. 通过 用户名获取 用户User user = userService.getUserByUserName(username);if (user == null) {return new ResponseBodyMessage<>(-1, "登录失败 , 无当前用户", false);}// 3. 获取到 user , 对密码进行校验boolean flag = passwordUtil.decrypt(password, user.getPassword());if (flag) {// 此时密码正确 , 登录成功// 创建 sessionHttpSession session = request.getSession(true);// 保存 usersession.setAttribute(Constant.USERINFO_SESSION_KEY, user);return new ResponseBodyMessage<>(1, "登录成功", true);}// 此时密码错误return new ResponseBodyMessage<>(-1, "登录失败", false);}/*** 2. 注册功能*/@RequestMapping(value = "/add")@Transactionalpublic ResponseBodyMessage<Boolean> addUser(User user, @RequestPart(required = false, value = "filename") MultipartFile file) {if (user == null) {return new ResponseBodyMessage(-1, "注册失败", false);}// 1. 判断 必填参数是否为空 (这里可以不写 ,前端大概率 是会判断的 。 )if ("".equals(user.getUsername())) {return new ResponseBodyMessage<>(-1, "注册失败, 当前用户为输入用户名", false);}if ("".equals(user.getPassword())) {return new ResponseBodyMessage<>(-1, "注册失败,当前用户未输入密码", false);}// 2. 校验用户名的 唯一性 :  如果 用户名已经纯在了 那么就不能注册User user2 = userService.getUserByUserName(user.getUsername());if (user2 != null) {return new ResponseBodyMessage<>(-1, "注册失败, 用户名已存在", false);}// 3. 手动设置 为 '' 的数据if ("".equals(user.getAddress())) {user.setAddress(null);}if ("".equals(user.getQq())) {user.setQq(null);}if ("".equals(user.getSex())) {user.setSex(null);}if ("".equals(user.getUrl())) {user.setUrl(null);}// 4. 对密码进行加密操作user.setPassword(passwordUtil.encrypt(user.getPassword()));// 5. 如果用户 上传了头像 ,可以将图片存入到本地if (file != null) {// 此时上传了头像 :// 获取到文件名 + 类型String fileNameAndType = file.getOriginalFilename();// 比如文件名为 : 阳台.png , 此时可以获取到 . 的 下标int index = fileNameAndType.lastIndexOf(".");// 从 index 位置开始截取String postfix = fileNameAndType.substring(index);// 判断一下 图片的格式是否符合预期要求if (".jpg".equals(postfix) || ".png".equals(postfix)) {// 通过 uuid 来设置文件名String uuid = IdUtil.simpleUUID();String imgFileStr = uuid + postfix;// 创建文件String path = IMAGE_PATH + imgFileStr;File imgFile = new File(path);if (!imgFile.exists()) {imgFile.mkdir();}try {
//                指定图片 , 上传之后的存储位置file.transferTo(imgFile);// 文件上传成功 :user.setUrl(imgFileStr);userService.addUser(user);return new ResponseBodyMessage<>(1, "注册成功", true);} catch (IOException e) {
//                e.printStackTrace();// 如果 上传失败 , 手动事务回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}// 此时 注册失败return new ResponseBodyMessage<>(-1, "注册失败", false);} else {return new ResponseBodyMessage<>(-1, "图片格式有误", false);}}// 6. 调用 userService 中的 addUser 方法 进行用户添加 (此时未上传图片 , 图片 为 默认)Integer ret = userService.addUser(user);if (ret != 1) {return new ResponseBodyMessage<>(-1, "注册失败", false);}return new ResponseBodyMessage<>(1, "注册成功", true);}@RequestMapping(value = "/getuser")public ResponseBodyMessage<User> getUserById(HttpServletRequest request) {// 1. 通过 session 获取 userHttpSession session = request.getSession(false);User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);// 2. 将密码置为空user.setPassword("");return new ResponseBodyMessage<>(1, "成功", user);}@RequestMapping(value = "/getuserbyid")public ResponseBodyMessage<HashMap<String, Object>> getUserById2(Integer userid) {HashMap<String, Object> result = new HashMap<>();if (userid == null || userid <= 0) {return new ResponseBodyMessage<>(-1, "获取失败!", null);}User user = userService.getUserById(userid);if (user == null) {return new ResponseBodyMessage<>(-1, "无当前用户!", null);}user.setPassword("");int blogNumber = blogService.getTextNumber(userid);int typeNumber = blogService.getType(userid);result.put("user", user);result.put("blogNumber", blogNumber);result.put("type", typeNumber);return new ResponseBodyMessage<>(1, "查询成功", result);}@RequestMapping(value = "/remove")public ResponseBodyMessage<Boolean> remove(HttpServletRequest request) {HttpSession session = request.getSession(false);session.removeAttribute(Constant.USERINFO_SESSION_KEY);return new ResponseBodyMessage<>(1, "成功", true);}}

3. mapper 包

3.1 UserMapper 接口

package com.example.blog_ssm.mapper;import com.example.blog_ssm.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;@Mapper
public interface UserMapper {// 1. 通过用户名 获取 用户User getUserByUserName(@Param("username") String username);// 2. 注册功能 (直接传一个 user 对象)Integer addUser(User user);// 3. 通过 用户id 获取 用户User getUserById(@Param("id") Integer id);}

3.2 BlogMapper 接口

package com.example.blog_ssm.mapper;import com.example.blog_ssm.model.Blog;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface BlogMapper {// 1. 获取 分类  (每篇小说的 类型)List<String> getType(@Param("userid") Integer userid);// 2. 通过 用户id 获取 当前用户的文章数量Integer getTextNumber(@Param("userid") Integer userid);// 3. 分页查询List<Blog> getListByPage(@Param("limit") Integer limit, @Param("offset") Integer offset);// 4. 返回总文章数Integer getTextCount();// 5. 通过 blogId 获取博客Blog getBlogById(@Param("blogId") Integer blogId);// 6. 增加博客Integer addBlog(@Param("userid") Integer userid, @Param("title") String title, @Param("content") String content, @Param("type") String type);}

4. model 包

4.1 User类

package com.example.blog_ssm.model;import lombok.Data;@Data
public class User {Integer id;String username;String password;String qq;String address;String createTime;String sex;String url;
}

4.2 Blog 类

package com.example.blog_ssm.model;import lombok.Data;@Data
public class Blog {private Integer blogId;private String title;private String content;private Integer userid;private String postTime;private String type;
}

5. service 包

5.1 UserService 类

package com.example.blog_ssm.service;import com.example.blog_ssm.mapper.UserMapper;
import com.example.blog_ssm.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;// 1. 根据用户名获取用户public User getUserByUserName(String username) {return userMapper.getUserByUserName(username);}// 2. 新增方法public Integer addUser(User user) {return userMapper.addUser(user);}// 3. 根据用户id获取用户public User getUserById(Integer id){return userMapper.getUserById(id);}}

5.2 BlogService 类

package com.example.blog_ssm.service;import com.example.blog_ssm.mapper.BlogMapper;
import com.example.blog_ssm.model.Blog;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class BlogService {@Autowiredprivate BlogMapper blogMapper;public Integer getType(Integer id) {List<String> ret = blogMapper.getType(id);if (ret == null) {return 0;}return ret.size();}// 通过 id 获取 当前 用户的 文章数public Integer getTextNumber(Integer id) {return blogMapper.getTextNumber(id);}// 获取 blog 表中的所有文章public Integer getTextCount() {return blogMapper.getTextCount();}// 通过分页获取 blogpublic List<Blog> getListByPage(Integer limit, Integer offset) {return blogMapper.getListByPage(limit, offset);}// 通过 blogId 获取博客public Blog getBlogById(Integer blogId) {return blogMapper.getBlogById(blogId);}public Integer addBlog(Integer userid ,String title, String content,String type){return blogMapper.addBlog(userid,title,content,type);}}

6. util 包

6.1 Constant 类

package com.example.blog_ssm.util;public class Constant {public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
}

6.2 PasswordUtil类

package com.example.blog_ssm.util;import cn.hutool.core.util.IdUtil;import cn.hutool.crypto.SecureUtil;import org.springframework.util.StringUtils;/*** 密码工具类*/public class PasswordUtil {/*** 1. 加密 (加盐)*/public  String encrypt(String password) {// 密码 : 随机盐值 + 密码String salt = IdUtil.simpleUUID();String finalPassword = SecureUtil.md5(salt + password);return salt + "$" + finalPassword;}/*** 解密** @param password 要验证的密码 (未加密)* @return 数据库中的加了盐值的密码*/public  boolean decrypt(String password, String securePassword) {boolean result = false;if (StringUtils.hasLength(password) && StringUtils.hasLength(securePassword)) {// 注意 : $ 是特殊字符 , 使用 split 分割时 需要转移if (securePassword.length() == 65 && securePassword.contains("$")) {// 随机盐值 为 32  , md5 加密的 密码 32 加上 $ 1字符 总共 65 字符String[] securePasswordArr = securePassword.split("\\$");// 盐值String salt = securePasswordArr[0];// 根据盐值 加密的密码String finalPassword = securePasswordArr[1];// 根据盐值 对新的密码进行加密password = SecureUtil.md5(salt + password);// 进行对比if (finalPassword.equals(password)) {result = true;}}}return result;}
}

6.3 ResponseBodyMessage 类

package com.example.blog_ssm.util;import lombok.Data;/*** 用来统一数据格式** @param <T>*/
@Data
public class ResponseBodyMessage<T> {// 1. 状态码private Integer status;// 2. 信息描述private String message;// 3. 数据private T data;public ResponseBodyMessage(Integer status, String message, T data) {this.status = status;this.message = message;this.data = data;}
}

7. Mybatis 包

7.1 UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.blog_ssm.mapper.UserMapper"><insert id="addUser">insert into user (username,password<trim prefix="," suffixOverrides=","><if test="qq!=null">qq,</if><if test="address!=null">address,</if><if test="sex!=null">sex,</if><if test="url!=null">url</if></trim>) values( #{username} , #{password}<trim prefix="," suffixOverrides=","><if test="qq!=null">#{qq},</if><if test="address!=null">#{address},</if><if test="sex!=null">#{sex},</if><if test="url!=null">#{url}</if></trim>)</insert><select id="getUserByUserName" resultType="com.example.blog_ssm.model.User">select *from userwhere username = #{username};</select><select id="getUserById" resultType="com.example.blog_ssm.model.User">select * from user where id = #{id};</select></mapper><!--分页公式 : (pageIndex - 1) * pageSize-->

7.2 BlogMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.blog_ssm.mapper.BlogMapper"><insert id="addBlog">insert into blog(title,content,type,userid) values(#{title},#{content},#{type},#{userid});</insert><!--通过 先 通过 where 选中 对应用户 然后 分组操作 group by 将他 文章的类型进行分组最后通过 count 聚合函数 拿到 分出来的组数 ,此时就是类型数了--><select id="getType" resultType="java.lang.String">select count(type) from blog where userid = #{userid} group by type;</select><select id="getTextNumber" resultType="java.lang.Integer">select count(title) from blog where userid = #{userid};</select><select id="getListByPage" resultType="com.example.blog_ssm.model.Blog">select * from blog order by postTime desc limit #{limit} offset #{offset} ;</select><select id="getTextCount" resultType="java.lang.Integer">select count(*) from blog;</select><select id="getBlogById" resultType="com.example.blog_ssm.model.Blog">select * from blog where blogId = #{blogId};</select></mapper><!--分页公式 : (pageIndex - 1) * pageSize-->

相关文章:

博客系统 实现 (前端 + 后端 )代码

文章目录博客系统前端代码 &#xff1a;1. add.html2. blog_detail.html3. blog_edit.html4. blog_list.html5. login.htmlcss 文件1. blog_detail.css2. blog_edit.css3. blog_list.css4. common.css5. login.css6. 分页器使用的 css后端代码1.config 包1.1 AppConfig类1.2 Lo…...

C语言:如何在cmd命令窗口上玩贪吃蛇游戏

最近在重新学习C语言知识,还别说,在这个过程中,我还真的学到了过去很多没有学习到C语言知识,于是就做了这个游戏–贪吃蛇. 运行结果如下: C语言:如何在cmd命令窗口上玩贪吃蛇游戏 文章目录 1. 实现原理2. 实现过程3. 参考代码1. 实现原理 其实,就是利用了人的视觉错觉来…...

Flutter-自定义图标

虽然Flutter有许多内置的icon图标&#xff0c;但是有些特殊功能的话&#xff0c;需要自定义图标或者需要在iconfont 阿里巴巴的图标库里找对应合适的图标。 第一步&#xff1a;在iconfont 阿里巴巴里搜索想要的图标并加入到购物车&#xff0c;点击下载代码后&#xff0c;会生成…...

教学场景应用视频试看预览功能

html5播放器视频预览功能效果 - 视频预览代码示例预播放一小段时间的视频内容&#xff0c;比如3分钟&#xff0c;然后引导用户付费观看或注册会员观看完整视频。原理&#xff1a;视频播放结束&#xff0c;执行s2j_onPlayOver()函数&#xff0c;显示提示信息或对话框&#xff0c…...

关于进程与进程调度

目录什么是进程进程管理进程的结构体(PCB)里的属性并行与并发什么是进程 一个运行起来的程序就是进程. 比如文件名是以 exe 结尾的就是一可执行文件(程序) 双击QQ.exe文件, 这个程序就跑起来了, 它在系统中形成了一个进程, 那我们怎么看到进程呢? 可以打开任务管理器, 点开进…...

Redis常用命令及数据类型参数

1. 针对于string SET key value / GET key SET k1 v1 GET k1 // v1String是二进制安全的&#xff0c;是可变长度的&#xff0c; 底层类似于ArrayList 是可扩容的&#xff0c;最大存储内存为 512MB。 2. 判断key中是否存在某个内容 EXISTS key SET k1 v1 EXISTS k1 // …...

(七十四)大白话深入探索多表关联的SQL语句到底是如何执行的?(2)

今天咱们就以MySQL单表查询来举例&#xff0c;看看执行计划到底包含哪些内容 其实只要大家跟着专栏一步一步的学习下来&#xff0c;会很轻松的看懂执行计划&#xff0c;但是如果你之前对什么数据页&#xff0c;索引&#xff0c;索引使用规则&#xff0c;这些东西学的不扎实&am…...

销售使用CRM系统集成Excel的五个技巧

销售过程中有很多情况会降低团队的效率。通过正确的实施CRM客户管理系统&#xff0c;可以帮助您的企业自动执行手动任务、减少错误并专注于完成交易。这里有5个技巧&#xff0c;可以帮助您的销售人员通过CRM集成Excel为销售流程赋能并提高他们的整体效率。 技巧1&#xff1a;将…...

过来人告诉你:Java学到什么程度可以找工作?

大部分初次学习Java的同学都非常关注自己学到什么程度可以找工作就业&#xff0c;因为学习的目的一方面在于掌握知识、提高技能&#xff0c;另一方面就是就业谋生。今天笔者就来跟大家聊一聊一下Java学习到什么地步可以面试找工作。任何企业&#xff0c;不论大小&#xff0c;对…...

【Linux】目录结构

Linux世界里&#xff0c;一切皆文件。 /bin&#xff1a;是Binary的缩写&#xff0c;这个目录存放着最经常使用的命令。&#xff08;常用&#xff09; /sbin&#xff1a;s就是Super User的意思&#xff0c;这里存放的是系统管理员使用的系统管理程序。 /home&#xff1a;存放普…...

37.Java进阶之实现动态编译

文章目录1. 作为程序员的最高追求2.如何实现动态编译2.1 生成源码2.2 调用编译器API对Test源码文件进行编译生成字节码2.3 调用类加载器对字节码进行加载得到Class对象2.4 使用Class对象创建对象进行使用3. Java编译API学习4. 类加载机制4.1 类加载过程4.2 类加载器的层次结构4…...

【Python百日进阶-Web开发-Vue3】Day549 - Vue3 商城后台 09:Veux4-01基本概念

文章目录 一、Vuex是什么?1.1 Vuex官网1.2 Vuex安装1.3 Vuex概述1.4 核心概念二、Vuex的基本使用2.1 简单使用2.1.1 `src/store/index.js`创建store并导出2.1.2 `main.js`中引入并`use(store)`2.1.3 `src/views/index.vue`首页中使用store2.2 使用`mapState`简化 `$store.stat…...

GitLab 解析:为什么市场正在转向一体化 DevSecOps 平台?(附Forrester完整报告下载)

本文来源&#xff1a;about.gitlab.com 译者&#xff1a;极狐(GitLab) 市场部内容团队 如 GitLab 预测&#xff1a;2023 年企业会将更多的时间和资源投入到持续的安全左移上&#xff08;详情请戳&#x1f449;&#xff1a;重磅&#xff01;GitLab 提出五大预测&#xff0c;洞见…...

ThreadLocal的内部结构和源码探究

目录一. ThreadLocal的内部结构1 常见的误解2 现在的设计3 这样设计的好处二. ThreadLocal的核心方法源码1 set方法2 get方法3 remove方法**4 initialValue方法**三. ThreadLocalMap源码分析1 基本结构2 弱引用和内存泄漏3 hash冲突的解决一. ThreadLocal的内部结构 ​ 通过之…...

Linux文件系统(下)

逻辑卷管理如果用标准分区在硬盘上创建了文件系统&#xff0c;为已有文件系统添加额外的空间多少是一种痛苦的体验。你只能在同一个物理硬盘的可用空间范围内调整分区大小。如果硬盘上没有地方了&#xff0c;你就必须弄一个更大的硬盘&#xff0c;然后手动将已有的文件系统移动…...

合并链表相关的练习

目录 一、合并两个有序链表 二、两数相加 一、合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&…...

FFmpeg介绍及入门知识

1、简介 FFmpeg是一套由c语言编写的&#xff0c;可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序,自身采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案&#xff0c;包含了非常先进的音频/视频编解码库libavcodec&#xf…...

ASA材料3D打印服务 抗紫外线材料3D打印服务 抗紫外线模型制作-CASAIM中科院广州电子

3D打印技术又称增材制造&#xff0c;通常是采用数字技术材料打印机来实现的&#xff0c;常在模具制造、工业设计等领域被用于制造模型&#xff0c;后逐渐用于一些产品的直接制造。随着 3D 打印逐渐成为主流生产流程的一部分&#xff0c;ASA抗紫外线材料应运而生。中科院广州电子…...

MySQL workbench数据表和数据结构

数据表和数据结构的关系 数据表 学号姓名位置26002351李晓丽126002589张明伟226003214李雪冬326002132汪涵426006541邱明罕526003654李丽6 怎样去描述上面的数据表&#xff0c;用【数据表结构】表示 表头字段名字段类型位数备注学号xuehao整数/字符8 姓名xingming字符4 座…...

网络与信息安全岗位介绍—售后工程师

售后工程师是提供客户技术支持和服务的专业人士。他们的任务是提供客户技术支持&#xff0c;安装、维护和修复系统或产品&#xff0c;遵从安全操作规范&#xff0c;排除计算机故障&#xff0c;以及解决其他技术疑难杂症。 售后工程师还管理、安装、升级和维护现有硬件和软件&a…...

Nowcoder .链表分割

文章目录哨兵位节点哨兵位节点 链表分割 小于X 尾插到一个新链表 大于等于X 尾插到另一个链表 最后将两个链表链接起来 需要注意的细节&#xff1a;将第一个链表的尾与第二个链表的头相连接&#xff0c;再返回连接后的整个链表的头&#xff08;哨兵位头节点的下一个&#xff0…...

猿创征文 | re:Invent 朝圣之路:“云“行业风向标

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; AWS 亚马逊云科技re:Invent全球大会 2022年亚马逊云科技re:Invent全球大会震撼来袭&#xff0c;即将于北京时间11月30日-12月2日在美国内华达州&#xff0c;拉斯维加斯…...

mysql的distinct和group by的区别

GROUP BY 和 DISTINCT 都是用于从数据库中选择唯一值的 SQL 子句。它们之间的主要区别在于它们的作用方式和应用场景。 GROUP BY 语句用于将数据按照一个或多个列进行分组&#xff0c;然后对每个组应用一个聚合函数&#xff08;如 COUNT、SUM、AVG 等&#xff09;以得到每个组…...

Web前端:前端开发人员的职责有哪些?

前端开发&#xff0c;就是要创造上面提到的网站面向用户的部分背后的代码&#xff0c;并通过建立框架&#xff0c;构建沉浸性的用户体验。前端工程师还需要确保网站在各种浏览器和设备上都能正常运行&#xff0c;并且能够根据用户需求不断优化和改进网站。前端开发人员的角色和…...

BatchNorm1d的复现以及对参数num_features的理解

0. Intro 以pytorch为例&#xff0c;BatchNorm1d的参数num_features涉及了对什么数据进行处理&#xff0c;但是我总是记不住&#xff0c;写个blog帮助自己理解QAQ 1. 复现nn.BatchNorm1d(num_features1) 假设有一个input tensor&#xff1a; input torch.tensor([[[1.,2.,…...

【专项训练】动态规划-1

动态规划 以上,并没有什么本质的不一样,很多时候,就是一些小的细节问题! 要循环,要递归,就是有重复性! 动态规划:动态递推 分治 + 最优子结构 会定义状态,把状态定义对 斐波那契数列 递归、记忆化搜索,比较符合人脑思维 递推:直接开始写for循环,开始递推 这里…...

软测面试了一个00后,绝对能称为是内卷届的天花板

前言 公司前段缺人&#xff0c;也面了不少测试&#xff0c;结果竟然没有一个合适的。一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资也不低&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。令我印象最深的是一个00后测试员&#xf…...

赢球票问题

题目描述 某机构举办球票大奖赛。获奖选手有机会赢得若干张球票。 主持人拿出 N 张卡片&#xff08;上面写着 1⋯N 的数字&#xff09;&#xff0c;打乱顺序&#xff0c;排成一个圆圈。 你可以从任意一张卡片开始顺时针数数: 1,2,3 ⋯⋯ 如果数到的数字刚好和卡片上的数字相…...

Go语言基础之Error接口

Go语言基础之Error接口1.Error 接口2.创建错误3.fmt.Errorf1.Error 接口 Go 语言中把错误当成一种特殊的值来处理&#xff0c;不支持其他语言中使用try/catch捕获异常的方式 Go 语言中使用一个名为 error 接口来表示错误类型 type error interface {Error() string }error 接…...

Sqoop详解

目录 一、sqoop基本原理 1.1、何为Sqoop&#xff1f; 1.2、为什么需要用Sqoop&#xff1f; 1.3、关系图 1.4、架构图 二、Sqoop可用命令 2.1、公用参数&#xff1a;数据库连接 2.2、公用参数&#xff1a;import 2.3、公用参数&#xff1a;export 2.4、公用参数&#xff…...