✏️作者:银河罐头
📋系列专栏:JavaEE
🌲“种一棵树最好的时间是十年前,其次是现在”
准备工作
创建项目,引入依赖,把之前写的前端页面拷贝进去。
依赖主要是:servlet, mysql, jackson
数据库设计
表设计
在当前的博客系统中,主要涉及到 2 个实体,博客 和 用户。
创建 2 张表,来表示博客和用户。用户和博客之间的关系是一对多。
把一些基本的数据库操作先封装好,以备后用。
-- 这个文件主要写建库建表语句
-- 建议 在建表的时候把 sql 语句保留下来,以便后续部署其他机器的时候就方便了。
create database if not exists java_blog_system;
use java_blog_system;
-- 删除旧表,重新创建新表
drop table if exists user;
drop table if exists blog;
-- 真正创建表
create table blog(
blogId int primary key auto_increment,
title varchar(128),
content varchar(4096),
postTime datetime,
useId int
);
create table user(
userId int primary key auto_increment,
username varchar(20) unique, -- 要求用户名和别人不重复
password varchar(20)
);
封装数据库的连接操作
public class DBUtil {
private static DataSource dataSource = new MysqlDataSource();
static {
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java_blog_system?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("123456");
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
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();
}
}
}
}
创建实体类
实体类,和表中记录对应的类。
blog 表,Blog 类对应。Blog 的一个对象,就对应表中的一条记录。
user 表,User 类对应。User 的一个对象,就对应表中的一条记录。
实体类里要有哪些属性,是和表里的列是密切相关的。
public class Blog {
private int blogId;
private String title;
private String content;
private Timestamp postTime;
private int userId;
public int getBlogId() {
return blogId;
}
public void setBlogId(int blogId) {
this.blogId = blogId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Timestamp getPostTime() {
return postTime;
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
}
public class User {
private int userId;
private String username;
private String password;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
封装数据库的增删改查
针对博客表,创建 BlogDao
针对用户表,创建 UserDao
提供一些方法,来进行增删改查。
Dao, Data Access Object 访问数据的对象
//通过这个类,封装对博客表的基本操作
public class BlogDao {
//1.新增一个博客
public void add(Blog blog) {
}
//2.根据 博客 id 来查询博客(博客详情页中)
public Blog selectById(int blogId){
return null;
}
//3.查询出数据库中所有的博客列表(博客列表页)
public List<Blog> selectAll(){
return null;
}
//4.删除指定博客
public void delete(int blogId){
}
}
//通过这个类,封装对博客表的基本操作
public class BlogDao {
//1.新增一个博客
public void add(Blog blog) {
Connection connection = null;
PreparedStatement statement = null;
try {
//1.建立连接
connection = DBUtil.getConnection();
//2.构造 sql
String sql = "insert into blog values(null, ?, ?, ?, ?)";
statement = connection.prepareStatement(sql);
statement.setString(1, blog.getTitle());
statement.setString(2,blog.getContent());
statement.setTimestamp(3,blog.getPostTime());
statement.setInt(4,blog.getUserId());
//3.执行 sql
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4.断开连接,释放资源
DBUtil.close(connection, statement, null);
}
}
//2.根据 博客 id 来查询博客(博客详情页中)
public Blog selectById(int blogId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1.和数据库建立连接
connection = DBUtil.getConnection();
//2.构造 SQL
String sql = "select * from blog while blogId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,blogId);
//3.执行 SQL
resultSet = statement.executeQuery();
//4.遍历结果集合
//blogId 是自增主键,是唯一的。所以要么是没有查到,要么是查到了一条记录
//此处可以不使用 where, 直接 if 判定即可
if (resultSet.next()){
Blog blog = new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
blog.setContent(resultSet.getString("content"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
blog.setUserId(resultSet.getInt("userId"));
return blog;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//5.释放资源,断开连接
DBUtil.close(connection,statement,resultSet);
}
return null;
}
//3.查询出数据库中所有的博客列表(博客列表页)
public List<Blog> selectAll(){
List<Blog> blogs = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1.建立连接
connection = DBUtil.getConnection();
//2.构造 SQL 语句
String sql = "select * from blog";
statement = connection.prepareStatement(sql);
//3.执行 sql 语句
statement.executeQuery();
//4.遍历结果集合
while(resultSet.next()){
Blog blog = new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
//注意这里的正文,博客列表页不需要把整个正文都显示出来
String content = resultSet.getString("content");
if(content.length() >= 100){
content = content.substring(0,100) + "...";
}
blog.setContent(content);
blog.setPostTime(resultSet.getTimestamp("postTime"));
blog.setUserId(resultSet.getInt("userId"));
blogs.add(blog);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection, statement, resultSet);
}
return blogs;
}
//4.删除指定博客
public void delete(int blogId){
Connection connection = null;
PreparedStatement statement = null;
try {
//1.建立连接
connection = DBUtil.getConnection();
//2.构建 SQL 语句
String sql = "delete from blog while blogId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,blogId);
//3.执行 sql
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4.关闭连接
DBUtil.close(connection,statement,null);
}
}
}
//针对用户表提供的基本操作
//由于没写注册功能,此处就不写 add 了
//也没有用户删号这个功能,也就不必 delete
public class UserDao {
//根据 userId 来查用户信息
public User selectById(int userId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1.建立连接
connection = DBUtil.getConnection();
//2.构造 SQL
String sql = "select * from user where userId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,userId);
//3.执行 sql
resultSet = statement.executeQuery();
//4.遍历结果集
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;
}
//根据 username 来查用户信息(登录的时候)
public User selectByUsername(String username){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1.建立连接
connection = DBUtil.getConnection();
//2.构造 SQL
String sql = "select * from user where username = ?";
statement = connection.prepareStatement(sql);
statement.setString(1,username);
//3.执行 sql
resultSet = statement.executeQuery();
//4.遍历结果集
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;
}
}
实现博客列表页
当前博客列表页上的数据都是写死的,正确的做法应该是从服务器获取数据并显示到页面上。
让博客列表页,加载的时候,通过 ajax 给服务器发一个请求,服务器查数据库获取博客列表数据,返回给浏览器,浏览器根据数据构造页面内容。
这样的交互过程,称为 “前后端分离”。
前端只是向后端索要数据,而不是请求具体的页面。后端也仅仅是返回数据。
这样设定的目的就是让前端和后端更加解耦。
由浏览器进行具体的页面渲染,减少了服务器的工作量。
上述是实现博客列表页的基本思路。
接下来需要:
1.约定前后端交互接口
获取博客列表功能,前端要发啥请求,后端要返回啥响应。
2.开发后端代码
3.开发前端代码
约定前后端交互接口
开发后端代码
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BlogDao blogDao = new BlogDao();
List<Blog> blogs = blogDao.selectAll();
//需要 把 blogs 转成符合要求的 json 字符串
String respJson = objectMapper.writeValueAsString(blogs);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
}
}
把 servlet 放到 api 包里,api 不一定非得是 类/方法,也可以是 “网络请求”(处理 http 请求,返回 http 响应)
开发前端代码
在博客列表页加载过程中,通过 ajax 访问服务器数据,再把拿到的数据构造到页面中。
<script src="./js/jquery.min.js"></script>
<script>
//在页面加载的时候,向服务器发起请求,获取博客列表数据
function getBlogs() {
$.ajax({
type:'get',
url: 'blog',
success: function(body) {
//响应的正文是 json 字符串,已经被 jquery 自动解析成 js 对象数组了
// for 循环遍历即可
let containerRight = document.querySelector('.container-right');
for(let blog of body){
//构造页面内容,参考之前写好的 html 代码
//构造整个博客 div
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.innerHTML = '查看全文 >>';
//希望点击之后能跳转到博客详情页
//为了让博客详情页知道是点了哪个博客,把 blogId 传过去
a.href = 'blog_detail.html?blogId=' + blog.blogId;
blogDiv.appendChild(a);
//把 blogDiv 加到父元素中
containerRight.appendChild(blogDiv);
}
}
});
}
//记得调用函数
getBlogs();
</script>
此时,博客列表页实现完成。
此时看的的博客列表页是空着的,因为博客列表的数据来自于数据库,而现在数据库是空着的。
-- 构造测试数据
insert into blog values(1, '这是我的第一篇博客', '从今天开始我要认真敲代码', now(),1);
insert into blog values(2, '这是我的第二篇博客', '从昨天开始我要认真敲代码', now(),1);
insert into blog values(3, '这是我的第三篇博客', '从前天开始我要认真敲代码', now(),1);
此处只是把 idea 当做是个 记事本,来记录下 sql 而已。真正要执行,要复制到 sql 客户端里执行。
有 2 个 bug,
1.不应该显示时间戳,而应该显示格式化时间
需要用到一个 格式化时间的类,转换一下。
SimpleDateFormat
public Timestamp getPostTimestamp() {
return postTime;
}
public String getPostTime(){
//把时间戳转换成格式化时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
return simpleDateFormat.format(postTime);
}
2.顺序,新的博客在上面,老的博客在下面。
实现博客详情页
接下来实现博客详情页,点击"查看全文"按钮,就能跳转到博客详情页中。跳转之后,在博客详情页中,对服务器发起 ajax 请求,从服务器获取数据,然后显示出来。
约定前后端交互接口
开发后端代码
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BlogDao blogDao = new BlogDao();
//尝试获取下 query string 中的 blogId字段
String blogId = req.getParameter("blogId");
if (blogId == null) {
//说明 query string 不存在,说明这次请求是在获取博客列表页
List<Blog> blogs = blogDao.selectAll();
//需要 把 blogs 转成符合要求的 json 字符串
String respJson = objectMapper.writeValueAsString(blogs);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
} else {
//说明 query string 存在,说明这次请求是在获取博客详情页
Blog blog = blogDao.selectById(Integer.parseInt(blogId));
if(blog == null) {
System.out.println("当前 blogId = " + blogId + " 对应的博客不存在!");
}
String respJson = objectMapper.writeValueAsString(blog);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
}
}
}
开发前端代码
在 blog_datail.html 中,加入 ajax,来获取数据。
<script src="js/jquery.min.js"></script>
<!-- 保证 这几个 js 的加载要在 jquery 之后,因为 edit.md 依赖 jquery-->
<script src="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.js"></script>
<script>
$.ajax({
type: 'get',
url: 'blog' + location.search,
success: function(body) {//回调函数
//处理响应结果,此处的 body 就表示一个博客的 js 对象
//1.更新标题
let titleDiv = document.querySelector('.title');
titleDiv.innerHTML = body.title;
//2.更新日期
let dateDiv = document.querySelector('.date');
dateDiv.innerHTML = body.postTime;
//3.更新博客正文
//此处不应该直接把博客内容填充到标签里
editormd.markdownToHTML('content',{ markdown: blog.content });
}
});
</script>
代码改完之后,重新启动服务器,发现此时博客详情页的结果还是之前未修改的状态。
始端用户访问加速节点时,如果该节点有缓存住了要被访问的数据时就叫做命中,如果没有的话需要回原服务器取,就是没有命中。
缓冲问题解决了,但是页面仍然不是预期的效果。
修改上述代码之后,发现正文有了,但是标题没出来。
就需要抓包,看下服务器返回结果是否符合预期,就可以确定是前端问题还是后端问题了。
响应结果是正确的,后端代码应该没问题。
接下来检查前端代码。
解决方案,把选择器写的更准确一些。
实现博客登录页
此处输入用户名,密码,点击登录,就会触发一个 http 请求。服务器验证用户名和密码,如果登陆成功,就跳转到博客列表页。
当前还只是一个 输入框,还不能提交请求,需要给改成 form 表单。
约定前后端交互接口
开发前端代码
在页面里加上 form 表单,使点击登录操作能 触发请求。
<!-- 垂直水平居中的登录对话框 -->
<div class="login-dialog">
<form action="login" method="post">
<h3>登录</h3>
<div class="row">
<span>用户名</span>
<input type="text" id="username" placeholder="手机号/邮箱" 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>
请求已经构造出来了。
开发后端代码
此处需要价格 servlet 来处理 登录请求。
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求的编码,告诉 servlet 按照啥格式理解请求
req.setCharacterEncoding("utf8");
//设置响应的编码,告诉 servlet 以啥样的格式构造响应
// resp.setCharacterEncoding("utf8");
resp.setContentType("text/html;charset=utf8");
//1.读取参数中的用户名,密码
//注意,如果用户名密码中存在中文,这里读取可能会乱码
String username = req.getParameter("username");
String password = req.getParameter("password");
if(username == null || "".equals(username) || password == null || "".equals(password)){
//登陆失败!
String html = "<h3> 登录失败! 缺少 username 或者 password 字段 </h3>";
resp.getWriter().write(html);
return;
}
//2.读一下数据库,看用户名是否存在,密码是否匹配
UserDao userDao = new UserDao();
User user = userDao.selectByUsername(username);
if(user == null){
//用户不存在
String html = "<h3> 登录失败! 用户名或密码错误 </h3>";
resp.getWriter().write(html);
return;
}
if(!password.equals(user.getPassword())){
//密码错误
String html = "<h3> 登录失败! 用户名或密码错误 </h3>";
resp.getWriter().write(html);
return;
}
//3.用户名密码验证通过,登陆成功,接下来创建会话,使用该会话保存用户信息
HttpSession session = req.getSession(true);
session.setAttribute("username", username);
//4.进行重定向,跳转到博客列表页
resp.sendRedirect("blog_list.html");
}
}
这样还是无法登录成功,因为数据库没有保存用户名密码。
构造一些测试数据,保存到数据库里。
登陆成功。
实现强制要求登陆
当用户访问博客列表页/详情页/编辑页,要求用户必须是已登录的状态,如果用户还没有登录,就会强制跳转到登录页面。
约定前后端交互接口
开发后端代码
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
//使用这个方法来获取用户的登录状态
HttpSession session = req.getSession(false);
if(session == null){
User user = new User();
String respJson = objectMapper.writeValueAsString(user);
resp.getWriter().write(respJson);
return;
}
User user = (User)session.getAttribute("user");
if(user == null){
user = new User();
String respJson = objectMapper.writeValueAsString(user);
resp.getWriter().write(respJson);
return;
}
//确实取出了 user 对象,直接返回即可
String respJson = objectMapper.writeValueAsString(user);
resp.getWriter().write(respJson);
}
开发前端代码
function checkLogin() {
$.ajax({
type: 'get',
url: 'login',
success: function(body) {
if(body.userId && body.userId > 0){
//登陆成功
console.log("当前用户已登录!");
} else {
//当前未登录,强制跳转到登录页
location.assign('blog_login.html');
}
}
});
}
checkLogin();
把这段代码加到 列表页,详情页,编辑页的代码中。
重启服务器之后,之前的登录状态就没了。
实现显示用户信息
目前页面的用户信息部分是写死的.
这个地方时写死的,希望能够动态生成。
1.如果是博客列表页,此处显示登录用户的信息。
2.如果是博客详情页,此处显示该文章的作者。
比如我以"张三"的身份登录,查看博客列表页时,左侧应该显示"张三"的用户信息,然后我点开李四写的博客,跳转到博客详情页,应该显示作者"李四"的信息。
约定前后端交互接口
列表页
function checkLogin() {
$.ajax({
type: 'get',
url: 'login',
success: function(body) {
if(body.userId && body.userId > 0){
//登陆成功
console.log("当前用户已登录!");
//把当前用户的名字显示到界面上
let h3 = document.querySelector('.container-left .card h3');
h3.innerHTML = body.username;
} else {
//当前未登录,强制跳转到登录页
location.assign('blog_login.html');
}
}
});
}
详情页
@WebServlet("/author")
public class AuthorServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String blogId = req.getParameter("blogId");
if(blogId == null){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("参数非法,缺少 blogId");
return;
}
//根据 blogId 查询 Blog 对象
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectById(Integer.parseInt(blogId));
if(blog == null){
//博客不存在
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("没有找到指定博客: blogId = " + blogId);
return;
}
//根据 Blog 中的 userId 找到 用户信息
UserDao userDao = new UserDao();
User author = userDao.selectById(blog.getUserId());
String respJson = objectMapper.writeValueAsString(author);
resp.setContentType("application/json; charset=utf8");
resp.getWriter().write(respJson);
}
}
function getAuthor() {
$.ajax({
type: 'get',
url: 'author',
success: function(body) {
//把 username 设置到界面上
let h3 = document.querySelector('.container-left .card h3');
h3.innerHTML = body.username;
}
});
}
getAuthor();
抓包后发现是少了 query string.
改下前端代码。
function getAuthor() {
$.ajax({
type: 'get',
url: 'author' + location.search,
success: function(body) {
//把 username 设置到界面上
let h3 = document.querySelector('.container-left .card h3');
h3.innerHTML = body.username;
}
});
}
getAuthor();
退出登录状态
注销(sign out)
判定登录状态:
1.看是否能查到 http session 对象;
2.看 session 对象里有没有 user 对象
实现退出登录,要么把 session 干掉,要么把 user 干掉。只要干掉一个就可以。
HttpSession 对象要想干掉,麻烦点。getSession 能够创建/获取会话,没有删除会话的方法。直接删除还不好删,可以通过设置会话的过期时间来达到类似的效果,但并不优雅。
更好的办法是把 user 干掉,通过 removeAttribute 就删了。
之前的逻辑中, httpSession 和 user 是一荣俱荣一损俱损的情况,但是引入注销逻辑后,就出现有 httpSession 没 user 的情况。
明确思路之后,先设计前后端交互接口。
约定前后端交互接口
开发后端代码
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession httpSession = req.getSession(false);
if(httpSession == null){
//未登录,提示出错
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前未登录!");
return;
}
httpSession.removeAttribute("user");
resp.sendRedirect("login.html");
}
}
开发前端代码
把 blog_detail.html, blog_edit.html, blog_list.html 这几个的 a 标签改下就行。
发布博客
写博客写了一些内容,点击"发布文章",没有反应。
约定前后端交互接口
开发后端代码
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BlogDao blogDao = new BlogDao();
//尝试获取下 query string 中的 blogId字段
String blogId = req.getParameter("blogId");
if (blogId == null) {
//说明 query string 不存在,说明这次请求是在获取博客列表页
List<Blog> blogs = blogDao.selectAll();
//需要 把 blogs 转成符合要求的 json 字符串
String respJson = objectMapper.writeValueAsString(blogs);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
} else {
//说明 query string 存在,说明这次请求是在获取博客详情页
Blog blog = blogDao.selectById(Integer.parseInt(blogId));
if(blog == null) {
System.out.println("当前 blogId = " + blogId + " 对应的博客不存在!");
}
String respJson = objectMapper.writeValueAsString(blog);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 发布博客
//读取请求,构造 blog 对象,插入数据库中
HttpSession httpSession = req.getSession(false);
if(httpSession == null){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前未登录,无法发布博客!");
return;
}
User user = (User) httpSession.getAttribute("user");
if(user == null){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前未登录,无法发布博客!");
return;
}
//确保登陆之后,就可以把作者拿到了
//获取博客标题和正文
String title = req.getParameter("title");
String content = req.getParameter("content");
if(title == null || "".equals(title) || content == null || "".equals(content)){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前提交数据有误,标题或正文为空!");
return;
}
//构造一个 blog 对象
Blog blog = new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setUserId(user.getUserId());
//发布时间,在 java 中生成 / 在数据库中生成都行
blog.setPostTime(new Timestamp(System.currentTimeMillis()));
//插入数据库
BlogDao blogDao = new BlogDao();
blogDao.add(blog);
//跳转到博客列表页
resp.sendRedirect("blog_list.html");
}
}
开发前端代码
把页面改造下,能够构造出请求。
<div class="blog-edit-container">
<form action="blog" method="post">
<!-- 博客标题编辑区 -->
<div class="title">
<input type="text" id="title" placeholder="输入文章标题" name="title">
<input type="submit" id="submit" value="发布文章">
</div>
<!-- 博客编辑器, 这里用 id 是为了和 markdown 编辑器对接 -->
<div id="editor">
<textarea name="content" style="display: none;"></textarea>
</div>
</form>
</div>
代码改完之后,再次运行,发现只显示一小段了。
前端代码有问题,看 chrome 开发者工具。
之前给编辑器设置的高度。
<form action="blog" method="post" style="height: 100%;">
发现乱码了?!
乱码是提交博客的时候乱的,还是获取博客的时候乱的?
这里大概率是提交的时候乱的,因为获取数据这个功能前面已经测试过了,而提交这个功能还没有测试过。
只要看下数据库是不是乱的。
应该是提交的时候就乱了。
把乱码的第4条删掉。
文章来源:https://www.toymoban.com/news/detail-412795.html
//获取博客标题和正文
req.setCharacterEncoding("utf8");
String title = req.getParameter("title");
String content = req.getParameter("content");
文章来源地址https://www.toymoban.com/news/detail-412795.html
到了这里,关于博客系统(前后端分离)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!