Javaweb项目 博客系统(后端代码编写)

准备工作,创建项目
引入依赖
1.servlet
2.mysql
3.jackson
导入前端代码
1.博客列表页
2.博客详情页
3.登录页
4.博客编辑页

接下来要进行的操作就是两大方面
1.前端和服务器的交互
2.服务器和数据库的交互

进行数据库设计创建数据库和数据表
一把需要把建库建表的操作写错sql文件然后保存下来
这时我们使用一个表表示博客 另一个表表示用户(创建表是根据需求来 博客系统中能够管理博客 也要进行登录等用户操作)

--编写SQL完成建库建表操作create database if not exists blog_system charset utf8;use blog_system;drop table if exists user;
drop table if exists blog;create table blog (blogId int primary key auto_increment,-- 博客标题title varchar(256),-- 博客内容content varchar(4096),-- 博客作者userId int,-- 博客发布时间postTime datetime
);
create table user(userId int primary key auto_increment,-- 用户名 指定用户名不能重复username varchar(64) unique,-- 密码password varchar(64)-- user 还可以设置其他数据属性 github链接 头像链接
);-- 构造一些数据
insert into user values(1,'zhangsan','123'),(2,'lisi','123');
insert into blog values(1,'第一篇博客','学习java第一天',1,'2024-01-01 12:00:00');
insert into blog values(2,'第二篇博客','学习java第二天',1,'2024-01-01 12:00:00');
insert into blog values(3,'第三篇博客','学习java第三天',1,'2024-01-01 12:00:00');

通过封装JDBC代码 来实现一些基础的数据库操作
在这个项目中 针对blog表和user表进行一些增删查改

DAO(Data Access Object)数据访问对象 写一些类 通过这些类里的方法封装了数据库操作 此时数据库就是通过这样的对象来访问的

package dao;import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;//通过这个类把数据库建立连接的逻辑进行封装public class DButil {//单例模式编写//并不会在外部使用所以使用static修饰方法private static volatile DataSource dataSource = null;private static DataSource getDataSource(){if (dataSource == null){synchronized (DButil.class){if(dataSource == null){dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/blog_system?useSSL=false&characterEncoding=utf8");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("123456");}}}return dataSource;}//提供一个方法和数据库建立连接public static Connection getConnection(){try {return getDataSource().getConnection();} catch (SQLException e) {e.printStackTrace();}return null;}//提供一个方法和数据库断开连接 进行资源释放public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){//如果把三个close放到一个try中一旦前面的close出现异常就会导致后面的close执行不到if(resultSet !=null){try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if(statement != null){try {statement.close();} catch (SQLException e) {e.printStackTrace();}if(connection != null){try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

封装数据库代码
1.设计数据库/设计表
2.封装DBUtil,实现建立连接和断开连接
3.创建实体类 后续数据库操作是围绕实体类展开的

实体类:数据库设计
根据需求找出有那些实体
在梳理清楚实体和实体之间的关系(一对一 一对多 多对多)
此处的实体类是要和数据库的表有对应关系的每个表都需要有实体类使用类的对象表示这个表的一条记录
此处的实体类一个是对应表User 一个是Blog

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.编写Dao类 来进行进一步的封装数据库操作

package dao;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;//通过这个类 进行封装针对blog表的增删改查
public class BlogDao {//1.新增一个博客//调用insert的时候 需要先构造一个blog对象//作为参数传递给insert 再由insert内部完成数据库插入操作public void insert(Blog blog)  {Connection connection = null;PreparedStatement statement = null;try{//1.和数据库建立连接connection = DButil.getConnection();//2.构造sql语句//此处的博客发部时间正好是sql执行的时候 使用sql里的now()函数完成获取当前时间String sql = "insert into blog values(null,?,?,?,now())";statement = connection.prepareStatement(sql);statement.setString(1, blog.getTitle());statement.setString(2, blog.getContent());statement.setInt(3, blog.getUserId());//3.执行sql语句statement.executeUpdate();}catch (SQLException e){e.printStackTrace();}finally {//4.关闭连接释放资源DButil.close(connection,statement,null);}}//2.查询表里所有的博客// 正常开发中 一把不会直接把整个表里的数据全部查询 一般都是条件查询或者分页查询public List<Blog> getBlogs(){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;List<Blog> blogs = new ArrayList<>();try {//1.和数据库建立连接connection = DButil.getConnection();//2.构造SQL语句String sql = "select * from blog";statement = connection.prepareStatement(sql);//3.执行SQLresultSet = statement.executeQuery();//4.遍历结果集合while (resultSet.next()){Blog blog = new Blog();blog.setBlogId(resultSet.getInt("blogId"));blog.setTitle(resultSet.getString("title"));blog.setContent(resultSet.getString("content"));blog.setUserId(resultSet.getInt("userId"));blog.setPostTime(resultSet.getTimestamp("postTime"));blogs.add(blog);}}catch (SQLException e){e.printStackTrace();}finally {DButil.close(connection,statement,resultSet);}//如果前面的查询出现问题blogs就会得到一个null的listreturn blogs;}//3.指定一个blogid 查询某一个博客public  Blog getBlog(int blogId){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = DButil.getConnection();String sql = "select * from blog where blogId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,blogId);resultSet = statement.executeQuery();//由于此处是按照blogId来查询 blogId又是主键//查询到结果要么是1条记录要么是0条记录 所以可以直接进行判定if (resultSet.next()){Blog blog = new Blog();blog.setBlogId(resultSet.getInt("blogId"));blog.setTitle(resultSet.getString("title"));blog.setContent(resultSet.getString("content"));blog.setUserId(resultSet.getInt("userId"));blog.setPostTime(resultSet.getTimestamp("postTime"));return blog;}}catch (SQLException e){e.printStackTrace();}return null;}//4.指定博客进行删除public void delete(int blogId){Connection connection = null;PreparedStatement statement = null;try {connection = DButil.getConnection();String sql = "delete from blog where blogId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,blogId);statement.executeUpdate();}catch (SQLException e){e.printStackTrace();}finally {DButil.close(connection, statement, null);}}
}

此处的JDBC代码是高度同质化的后面会使用Mybatis给数据库操作代码消除掉

下面是关于UserDao的JDBC代码

package dao;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;//通过这个类 进行封装针对User表的增删改查
public class UserDao {//1.根据userId来查询用户信息public User getUserById(int userId){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try{connection = DButil.getConnection();String sql = "select * from user where userId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,userId);resultSet = statement.executeQuery();if(resultSet.next()){User user = new User();user.setUserId(resultSet.getInt("userId"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));return user;}}catch (SQLException e){e.printStackTrace();}finally {DButil.close(connection,statement,resultSet);}return null;}//2.根据username来查询用户信息public User getUserByname(String username){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = DButil.getConnection();String sql = "select * from user where username = ?";statement = connection.prepareStatement(sql);statement.setString(1,username);resultSet = statement.executeQuery();if (resultSet.next()){User user = new User();user.setUserId(resultSet.getInt("userId"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("passoword"));return user;}}catch(SQLException e){e.printStackTrace();} finally{DButil.close(connection,statement,resultSet);}return null;}}

上述代码 完成类数据库相关的工作
接下来就可以进行前后端交互逻辑的实现了 以功能为维度展开分别进行"设计前后端交互接口" “后端开发代码” “前端开发代码” “调试”

功能一:实现博客列表页 让博客列表页能够加载博客列表
之前显示的内容都是在html中写死的 此处应该从数据库中获取

之后我们要做的就是 让博客列表在加载的时候发起一个ajax的http请求 请求发到服务器上 就能获取到博客列表的数据 进一步把博客数据展示到页面上(这就涉及前端和后端交互)
1.前端发一个HTTP请求向后端索要博客列表数据
2.后端收到请求之后查询数据库获取到数据库中的博客列表返回给前端
3.前端拿到响应之后就依据这里的内容构造出html片段最终显示出来

在进行这三个操作之前 还需要先约定前后端交互接口后端和前端要进行很多种不同的数据交互 每一种数据交互 都需要发送不同的请求返回不同的响应

这里这么约定都行 下面是一种典型的约定方法
此处是获取博客列表 此处不需要加上一些额外的参数
后续实现获取博客详情就需要指定blogId 就可以通过query string 或者 body传递给后端

请求 GET blog
响应
HTTP/1.1 200 OK
Content-Type: applicattion/json [
{
blogId:1
title:
content:
userId:
postTime:
}
{
blogId:2
title:
content:
userId:
postTime:
}
]

编写后端代码
后端代码要做的事就是 当收到上述请求之后 就会构造并返回一个约定响应的数据

package api;import com.fasterxml.jackson.databind.ObjectMapper;
import dao.Blog;
import dao.BlogDao;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {BlogDao blogDao = new BlogDao();List<Blog> blogs = blogDao.getBlogs();//这里jackson看到blogs是一个数组就会构造出一个json数组 //然后针对List中的每个Blog对象 分别构造出json对象//具体构造过程就是根据Blog的属性 属性的名字 就是json都key 属性的值就是json的valueString respJson = objectMapper.writeValueAsString(blogs);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}
}

在这里插入图片描述

{
blogId:1
title:
content:
userId:
postTime:
}

编写前端代码
让页面通过js ajax的发起http请求 来获取到刚才服务器这里的数据

    <script src = "https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script><script>// 编写js代码// 构造http请求 获取到博客列表数据 并展示到页面上function getBlogs() {$.ajax({type : 'get',url : 'blog',success : function(body) {// 根据响应的内容 构造出 html 片段 展示到页面上// 由于服务器响应已经设置了Content-Type为application/json内容所以此时就会自动把此处的响应内容解析成js对象数组let container = document.querySelector('.container-right');for(let blog of body){// 根据当前blog构造一个html片段let blogDiv = document.createElement('div');blogDiv.className = 'blog';//构造标题let titleDiv = document.createElement('div');titleDiv.className = 'title';titleDiv.innerHTML = blog.title;blogDiv.appendChild(titleDiv);//构造发布时间let dateDiv = document.createElement('div');dateDiv.className = 'date';dateDiv.innerHTML = blog.posttime;blogDiv.appendChild(dateDiv);//构造发布信息let descDiv = document.createElement('div');descDiv.className = 'desc';descDiv.innerHTML = blog.content;blogDiv.appendChild(descDiv);//构造查看全文按钮let a = document.createElement('a');a.href = 'blog_datail.html?blogId=' + blog.blogId;a.innerHTML = '查看全文 &gt;&gt';blogDiv.appendChild(a);//最后把拼好的blogDiv添加在contationer的后面container.appendChild(blogDiv);}    }});}getBlogs();</script>

然后我们访问清单网页就会导入我们数据库的内容
在这里插入图片描述

在这里插入图片描述
打开一个博客列表此处涉及到两个http请求 一个请求时获取博客列表页这个静态 一个时获取博客数据的
在这里插入图片描述
在这里插入图片描述

当前我们显示的是时间戳所以要对其进行转化
这里需要明确问题是在前端还是在后端
1.后端返回时间戳
2.后端返回是格式化时间 但是前端显示了时间戳
对此问题我们可以通过抓包来了解
在这里插入图片描述
可以看到抓到两个http请求第一个请求是获取blog_list.html这个页面
一个是后端代码请求
我们可以看到后端的代码就已经是一个时间戳了 所以此时我们后端就要做一个格式化的时间 在后端解决问题
在这里插入图片描述
在这里插入图片描述
1.看到blogs是一个list 生成结果就是json数组
2.数组的每个元素(blog对象)分别转换成json字符串
3.转换成的字符串根据blog对象的getter方法来完成的

jackson就会自动调用这里的getPostime 把得到的结果作为json字符串中postTime属性的值
在这里插入图片描述
此处就回返回一个Timstamp这个类型就被jackson当成时间戳来显示
时间戳=>格式化时间(Java标准库中提供了一个SimpleDateFormat类 完成这个工作)
1.先构造一个对象构造的时候指定具体的格式
2.使用format方法得到格式化

在这里插入图片描述

实现博客详情页
此处的步骤和之前的类似
1.约定前后端交互接口

请求: GET/blog?blogId=1
响应: HTTP/1.1 200 OK
Content-Type:application/json
{ blogId:1 title:“学习java第一天”
content:“今天学习情况”
userId:1
postTime:“时间”
}

2.实现后端代码

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {BlogDao blogDao = new BlogDao();//现尝试获取下blogId这个参数 看看能不能获取到String blogId = req.getParameter("blogId");if(blogId == null){//此时就是获取博客列表 没有blogId参数//这里jackson看到blogs是一个数组就会构造出一个json数组//然后针对List中的每个Blog对象 分别构造出json对象//具体构造过程就是根据Blog的属性 属性的名字 就是json都key 属性的值就是json的valueList<Blog> blogs = blogDao.getBlogs();String respJson = objectMapper.writeValueAsString(blogs);//此处把java对象数组 转成了json字符串resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}else {//此时就说明获取的是博客详情 有blogId参数//这里获取的id得到的是一个字符串 所以要把它转成int类型Blog blog = blogDao.getBlog(Integer.parseInt(blogId));if(blog == null){//返回一个id为0的blog对象 前端再根据这里进行进行判定//id不为空 但是输入的query不存在 例如输入的id是100000000blog = new Blog();}String respJson = objectMapper.writeValueAsString(blog);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}}
}

3.实现前端代码
文档对象模型(DOM)
HTML上的每个元素 都会对应到一个js的对象
这个对象是已经创造的
通过querSelector就能把这个对象找到

在这里插入图片描述
这里是先找到有没有container-right标签 再看看标签里有没有h3标签
一旦把js对象内容进行修改了 界面内容就会进行改变

引入依赖的顺序 editor.md依赖了jquery 所以我们在引入editor之前要先引入jquery依赖

实现登录详情页

在页面输入用户名 和 密码
点击登录之后 就会触发登录逻辑 如果登录成功 就会重定向到 博客列表
1.前后端交互接口

POST/login Content-Type: application/x-www-form-urlencoded
(使用form表单的方式提交)
username=zhangsan&password=123
响应 HTTP/1.1 302
Location:blog_list.html(登录之后就会重定向到列表页面)

2.编写后端代码
新写一个servlet处理login这个请求路径
每个servlet都会关联一个路径 前面博客列表博客详情页都属于blog这个路径 一个servlet就行
此处需要一个login的路径

package api;import dao.User;
import dao.UserDao;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.获取请求中用户名和密码//给请求对象设置字符集使其请求中username或者password是中文也能处理req.setCharacterEncoding("utf8");String username = req.getParameter("username");String password = req.getParameter("password");if(username == null || password == null || username.equals("") || password.equals("")){resp.setContentType("text/html; charset=utf8");resp.getWriter().write("输入的用户名或者密码为空");return;}//2.和数据库验证 看当前用户名和密码是否匹配UserDao userDao = new UserDao();User user = userDao.getUserByname(username);if(user == null){//提交的用户名错误resp.setContentType("text/html; charset=utf8");resp.getWriter().write("用户名或密码错误!");return;}if(!password.equals(user.getPassword())){//当前提交的密码有误resp.setContentType("text/html; charset=utf8");resp.getWriter().write("用户名或密码错误!");return;}//3.创建会话HttpSession session = req.getSession(true);}
}

创建会话方法参数true表示不存在就创建 存在就查询 并且生成键值对(key就是sessionId
value就是HttpSession对象) 通过sessionId通过set-Cookie返回到浏览器

3.写前端代码

<div class="login-container"><!-- 登录对话框 --><div class="login-dialog"><h3>登录</h3><!-- 使用 form 包裹一下下列内容, 便于后续给服务器提交数据 --><form action="login" method="post"><div class="row"><span>用户名</span><input type="text" id="username" name="username"></div><div class="row"><span>密码</span><input type="password" id="password" name="password"></div><div class="row"><input type="submit" id="submit" value="登录"></div></form></div></div>
</body>
</html>

实现强制检查功能
此处要求系统必须要登录才能使用 用户在未登录博客详情页列表页就会自动跳转到登录页
1.约定前后端交互接口
在博客详情页列表页 发起一个get 的 ajax 询问服务器是否登录
请求:
GET login
响应:
HTTP/1.1 200 OK(已登录)
HTTP/1.1 403 Forbidden(未登录)
2.编写后端代码

 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//会话不存在 就认为未登录HttpSession session = req.getSession(false);if(session == null){resp.setStatus(403);return;}//如session存在 就查看User对象是否存在User user = (User) session.getAttribute("user");if(user==null){resp.setStatus(403);return;}//若是会话存在而且用户存在就返回 200 状态码表示已登录resp.setStatus(200);}

3.编写前端代码
在每段前端html文件上加上一个js方法

function checklogin(){$.ajax({type : 'get',url: 'login',success: function(body){},error: function(body){location.assign("login.html");}});
}

实现显示博客详情页
(如果使用zhangsan这个用户列表页就应该是张三用户信息)
1.约定前后端交互接口

博客列表页:
请求: GET/user
响应: HTTP/1.1 200 OK
{ userId:1,username:‘zhangsan’} 博客详情页
请求: GET/user?blogId=1
响应: HTTP/1.1 200 OK
{ userId:1 username:“zhangsan” }

2.编写后端代码

package api;import com.fasterxml.jackson.databind.ObjectMapper;
import dao.Blog;
import dao.BlogDao;
import dao.User;
import dao.UserDao;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/user")
public class UserServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String blogId = req.getParameter("blogId");if(blogId == null){//从博客列表页//从seeion中拿到user对象HttpSession session = req.getSession(false);if(session == null){User user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);return;}User user = (User) session.getAttribute("user");if(user == null){user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);return;}String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}else {//博客详情页//需要查询数据库BlogDao blogDao = new BlogDao();Blog blog = blogDao.getBlog(Integer.parseInt(blogId));if(blog == null){User user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);return;}UserDao userDao = new UserDao();User user = userDao.getUserById(blog.getUserId());if(user == null){user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);return;}String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}}
}

先从请求中拿到blogId然后如果blogid为空 就从请求中拿到一个会话session 如果会话为空就返回一个respJson格式字符串 这个json格式字符串中里面具体内容是{userId:0,username:“”…}

为什么返回的是一个空的user而不是null?
这是因为ajax要求返回的类型是一个userjson的格式
如果返回的是一个null就会报错

退出登录(注销)
判定登陆状态逻辑有两点
1.会话存在
2.会话中存储user对象两个条件同时具备才认为用户已经登录
我们只要破坏上诉任何一个条件就可以达成注销效果
在此我们可以使用Servlet中的api删除user(Attribute)

还是按照之前的三个步骤展开
1.约定前后端交互接口
请求

GET/logout

响应

HTTP/1.1 302
Location:login.html

2.编写后端代码

package api;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//先获取到请求中的sessionHttpSession session = req.getSession(false);//如果会话为空就是未登录的状态 返回到登录界面if(session == null){resp.sendRedirect("login.html");return;}//如果之前登录成功了就会给session中存储一个user这样的会话Attribute//我们把这个user删除就会 判定未登录了session.removeAttribute("user");resp.sendRedirect("login.html");}
}

3.编写前端代码
我们可以通过一个a标签href属性 指定要访问的路径就可以了
点击a标签就能触发http get请求

发布博客
本质上和登录类似
核心是通过form表单 把页面用户输入内容提交到服务器这边服务器就可以把内容保存到数据库中即可
1.约定前后端交互接口
使用form提交数据
请求

POST/blog
Content-Type:application/x-www-from-urlencoded
title=xxx&content=xxxx

响应

HTTP/1.1 302
Location:blog_list.html

提交之后就能看到新发布的博客了
2.编写后端代码

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.获取到登录用户HttpSession session = req.getSession(false);if(session == null) {resp.setContentType("text/html; charset=utf8");resp.getWriter().write("用户未登录!");return;}User user = (User) session.getAttribute("user");if(user == null){resp.setContentType("text/html; charset=utf8");resp.getWriter().write("用户未登录!");return;}//2.获取到请求中传递的内容//记得设置编码req.setCharacterEncoding("utf8");String title = req.getParameter("title");String content = req.getParameter("content");if(title == null || content == null || "".equals(title) || "".equals(content)){resp.setContentType("text/html; charset=utf8");resp.getWriter().write("标题或正文为空");return;}//3.构造Blog对象 并且插入数据库之中Blog blog = new Blog();blog.setTitle(title);blog.setContent(content);blog.setUserId(user.getUserId());BlogDao blogDao = new BlogDao();blogDao.insert(blog);//4.反转到博客列表resp.sendRedirect("blog_list.html");}

3.编写前端代码
把from表单补齐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/321999.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言实验-数组、字符串以及指针

一&#xff1a; 求一个NN矩阵主、次对角线上所有元素之和。矩阵输入、矩阵输出、矩阵对角线求和分别用三个子函数实现。&#xff08;N的值由用户从键盘输入&#xff09; #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h>void print(int(*arr…

323_C++_QT_QProcess执行cmd解压、压缩、删除tar.gz等等其他压缩包文件到指定目录,不需要外部库,QT自带API的就行

// decompressPath : 解压到此目录 // fileName : 解压的tar.gz文件名executeCommand(decompressPath , QString::fromStdString(fileName));// 开始解压 void executeCommand

获取和修改线程的id和名称

当创建两个线程时&#xff0c;需要获取线程的id和名称&#xff0c;这样可以知道是哪个线程执行的 方式1&#xff1a;this.getId()和this.getName() 写代码注意点&#xff1a;要写对类名 方式2&#xff1a;Thread.currentThread().getId()和Thread.currentThread().getName() 修…

初识Node.js-REPL(详解交互式解释器)

目录 一、REPL介绍 1.概念 2.主要特点和用途 3.应用 二、 REPL语法 1.简单的表达式运算 2.使用变量 3.多行表达式 下划线(_)变量 三、REPL 命令 四、停止 REPL 五、Gif 实例演示 六、REPL应用实例 七、总结 一、REPL介绍 1.概念 Read&#xff08;读取&#xff09…

类和对象、this指针、类里的默认生成函数

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

如何恢复回收站中被删除的文件?3个恢复策略,实测有用!

“刚刚一不小心把回收站清空了&#xff0c;大家有什么好用的方法可以帮我恢复回收站中删除的文件吗&#xff1f;快帮帮我吧&#xff01;” 在使用电脑的过程中&#xff0c;我们有时可能会不小心将重要的文件或文件夹删除到回收站&#xff0c;并且随后可能进一步从回收站中彻底删…

【Git】Git学习-17:git rebase,且解决合并冲突

学习视频链接&#xff1a;【GeekHour】一小时Git教程_哔哩哔哩_bilibili​编辑https://www.bilibili.com/video/BV1HM411377j/?vd_source95dda35ac10d1ae6785cc7006f365780 理论 git rebase 目标分支&#xff1a;把当前分支的提交&#xff0c;从与目标分支的共同主祖先处断开…

【linux】dmesg工具

dmesg介绍 dmesg工具用途&#xff1a; dmesg - print or control the kernel ring buffer kernel ring buffer, 内核环形缓冲区&#xff0c;也叫环形队列&#xff0c;Linux内核日志就存储在一个环形队列中&#xff0c;环形队列满的时候&#xff0c;新的消息会覆盖掉旧的消息。…

UE5自动生成地形一:地形制作

UE5自动生成地形一&#xff1a;地形制作 常规地形制作地形编辑器地形管理添加植被手动修改部分地形的植被 置换贴图全局一致纹理制作地貌裸露岩石地形实例 常规地形制作 地形制作入门 地形导入部分 选择模式&#xff1a;地形模式。选择地形子菜单&#xff1a;管理->导入 …

Windows电脑搭建HarmonyOS NEXTDeveloper Preview2环境详解

Windows电脑搭建HarmonyOS NEXTDeveloper Preview2环境详解&#xff1a; HarmonyOS NEXT Preview系列教程基于Api11讲解-IT营大地老师 1 、电脑要求以及注意事项 操作系统 &#xff1a; Windows10 64 位、 Windows11 64 位 内存 &#xff1a; 8GB 及以上&#xff0c;推荐 16G…

“情况不明,对子先行”攻略

掼蛋作为一种策略性极强的游戏&#xff0c;不仅考验牌技&#xff0c;更考验玩家的智慧和策略布局。这里主要介绍一下当牌力不足的时候的普通策略—情况不明&#xff0c;对子先行。 当你的牌力不强&#xff0c;或者牌局情况不明朗时&#xff0c;自己手上有有比较多的对子&#x…

【Ansible】ansible-playbook剧本

playbook 是ansible的脚本 playbook的组成 1&#xff09;Tasks&#xff1a;任务&#xff1b;通过tasks 调用ansible 的模板将多个操作组织在一个playbook中运行 2&#xff09;Variables&#xff1a;变量 3&#xff09;Templates&#xff1a;模板 4&#xff09;Handles&#xf…

如何开发自己的深度学习优化算法

深度学习优化算法 如何开发自己的深度学习优化算法理解优化算法的基础**核心组件**&#xff1a; 设计自定义优化算法的步骤**步骤 1: 定义问题和目标****步骤 2: 研究现有算法****步骤 3: 开发初步想法****步骤 4: 创建原型****步骤 5: 系统测试与优化** 关键建议 如何开发自己…

C 语言指针怎么理解?

在今天的学习中&#xff0c;我注意到有位学员似乎对 C 语言指针的理解有些困惑。为了帮助大家更好地理解&#xff0c;我来举个例子。 C 语言指针就好比 Windows 桌面上常见的快捷方式。快捷方式可以指向某个游戏&#xff0c;这就是普通指针&#xff1b;它也可以指向另一个快捷…

Apache DolphinScheduler 3.3.0 版本重磅更新提前看!

Apache DolphinScheduler 3.3.0版本终于要在万众期待中发布啦&#xff01;本次发版将有重大功能更新&#xff0c;包括架构上的调整。 为了让广大用户提前尝鲜&#xff0c;社区特别准备了直播活动提前揭秘3.3.0版本中的重要更新&#xff0c;到时候你将会了解到这些信息&#xf…

(四)小程序学习笔记——自定义组件

1、组件注册——usingComponents &#xff08;1&#xff09;全局注册&#xff1a;在app.json文件中配置 usingComponents进行注册&#xff0c;注册后可以在任意页面使用。 &#xff08;2&#xff09;局部注册&#xff0c;在页面的json文件中配置suingComponents进行注册&#…

vector、heap数组、stack数组访问性能验证

测试目的 本次测试旨在比较不同数据结构&#xff08;vector、数组&#xff09;以及不同访问方法&#xff08;[]、at()、offset&#xff09;在性能上的差异&#xff0c;从而为开发者提供在特定情境下做出最佳选择的依据。 测试代码 测试网址:Quick C Benchmarks 使用GCC9.5 …

pxe远程安装

PXE 规模化&#xff1a;可以同时装配多台服务器 自动化&#xff1a;自动安装操作系统和各种配置 不需要光盘U盘 前置需要一台PXE服务器 pxe是预启动执行环境&#xff0c;再操作系统之前运行 实验&#xff1a; 首先先关闭防火墙等操作 [rootlocalhost ~]# systemc…

C++成员初始化列表

我们在类的构造函数中使用成员初始化列表可以带来效率上的提升&#xff0c;那么成员初始化列表在编译后会发生什么就是这篇文章要探究的问题 文章目录 引入成员初始化列表用成员初始化列表优化上面的代码成员初始化列表展开成员初始化列表的潜在危险 参考资料 引入 考虑下面这…

电脑提示mfc140u.dll文件丢失了?怎么快速修复mfc140u.dll文件

当你的电脑提示你的mfc140u.dll文件丢失了&#xff0c;那么就要小心了&#xff0c;可能你的某些程序出问题了&#xff01;这时候需要我们去进行相关的修复&#xff0c;只有修复了这个mfc140u.dll文件&#xff0c;才能正常的使用某些程序。下面一起来了解一下mfc140u.dll文件吧。…