个人博客-javaWeb项目

article/2025/9/11 12:48:08

一、目标

利用已有的前端页面实现一个个人博客系统的后端设计,可以实现用户登录,博客列表展示,博客详情页展示,写博客,删除博客的功能。

二、开发思路

采用前后端分离的方式,网页通过ajax构造HTTP请求和服务端进行数据交互,服务器端接收的请求通过servle解析请求,并返回响应数据,网页拿到响应数据解析后再根据数据的内容渲染到页面。

三、环境准备

JDK、maven、MySQL、相关依赖包5个:lombok(自动生成getter、setter等)、javax.servlet-api(servlet包)、mysql-connector-java(mysql包)、jackson-databind(json数据解析包,用于json序列化和反序列化)、junit(单元测试框架)

四、数据库相关设计

1.数据库设计

数据库设计两张表:
· 用户表用于存放用户信息;
· 文章表存放博客信息。
在这里插入图片描述

create table user(id int primary key auto_increment,username varchar(20) not null unique,password varchar(256) not null,nickname varchar(20),head varchar(20),github varchar(256)
)comment '用户表';create table article(id int primary key auto_increment,title varchar(256) not null,content mediumtext not null,create_time datetime,user_id int,foreign key(user_id) references user(id))comment '文章表';

2.实体类设计

在数据库设计好后, 为每张表设计实体类,以字段为成员变量,之所以要设计实体类,是因为在http提交数据的时候,服务端会把数据转换为java对象,同时在服务端返回数据的时候,返回的也是java对象之后转换为json字符串。

@Getter
@Setter
@ToString
public class Article {private Integer id;private String title;private String content;private java.util.Date createTime;private Integer user_id;}@Getter
@Setter
@ToStringpublic class User {private  Integer id;private String  username;private String password;private String nickname;private String head;private String github;
}

3.JDBC

JDBC步骤:
(1)创建数据库连接对象(这里通过单例模式数据库连接池来创建);
(2)创建操作命令对象(通过连接对象+带占位符的SQL创建)
(3)执行SQL,在执行前要替换掉占位符
(4)如果是:插入、修改、删除需要返回Int类型(说明成功操作了几条)。查询则需要返回查询结果集(一条数据就转为一个Java对象,多条数据需要利用ArrayList< T>)
(5)释放资源

  • 在JDBC的第一部分,可以将获取数据库的连接封装起来,采用单例模式。这样做的目的是只创建一个连接池来获取多个连接对象。具体操作如下:
    1.创建util工具包,用来存放连接,包括:封装数据库连接和封装session会话管理。
    在这里插入图片描述
    2.双重校验锁实现线程安全的单例模式
public class DButil {/** 1.封装获取数据库连接;* 单例模式* */private static volatile javax.sql.DataSource DS;private static DataSource getDataSource(){if(DS==null){synchronized (DButil.class){if(DS==null){MysqlDataSource ds=new MysqlDataSource();ds.setURL("jdbc:mysql://localhost:3306/blog_java44");ds.setUser("root");ds.setPassword("******");ds.setUseSSL(false);ds.setCharacterEncoding("utf8");DS=ds;}}}return DS;}//提供一个开放出来给jdbc操作的代码使用工具:获取连接对象public static java.sql.Connection getConnection(){try {return getDataSource().getConnection();} catch (SQLException e) {throw new RuntimeException("获取数据库连接失败");}}//释放资源public static void close(Connection c, Statement s, ResultSet re){try {if(re!=null) re.close();if(c!=null) c.close();if(s!=null) s.close();} catch (SQLException e) {throw new RuntimeException("jdbc释放资源出错",e);}}public static void close(Connection c, Statement s){close(c,s,null);}//@test是单元测试注解,可以直接运行(必须 public void)@Testpublic void test(){Assert.assertNotNull(getConnection());
//        System.out.println(getConnection());}
}

在最后对连接是否成功进行一个单元测试:使用了一个Assert断言来判断获取对象是否为空。
注:如果报错,说明单元测试不通过。没有报错返回true,则说明单元测试通过。

五、servlet相关设计

1.对session的封装

登录功能里需要有会话管理,
(1)会话管理包括:登录成功后创建session并保存用户信息以及访问敏感资源后校验session,查看用户是否登录。所以考虑把session的校验功能封装起来,以供多处代码的使用。

涉及的问题:

  • 如何判断用户是否登录–》返回登录时的用户信息即可。
  • 如何设计返回值–》返回用户信息User(如果已经登录就返回User,没登陆就返回Null)

(2)Servlet处理请求和响应时要用到序列化及反序列化,因此考虑将两个功能也封装起来。

  • 序列化:用于返回响应数据,把Java对象转为json字符串。在序列化的同时把响应写入响应体发出去。
  • 反序列化:用于把请求正文中的json字符串转换为Java对象,方便后端操作。
  • 因为原始的日期不是我们想要的形式,所以日期需要格式化一下:可以写个静态代码块,在初始化时就设置ObjectMapper的日期格式
public class WebUtil {
//简单起见,使用了饿汉式单例模式private static final ObjectMapper MAPPER=new ObjectMapper();static {DateFormat df=new SimpleDateFormat("yyyy-MM-dd");MAPPER.setDateFormat(df);}public static User validateLogin(HttpServletRequest req){HttpSession session=req.getSession(false);//从request对象获得session对象User user=null;if(session!=null){user=(User) session.getAttribute("user");}return user;}public static void serialize(HttpServletResponse resp, Object o){try {resp.setContentType("utf-8");resp.setContentType("application/json");String body=MAPPER.writeValueAsString(o);resp.getWriter().write(body);} catch (IOException e) {throw new RuntimeException("序列化出错",e);}}public static <T> T deserialize(HttpServletRequest req,Class<T> clazz){try {return MAPPER.readValue(req.getInputStream(),clazz);} catch (IOException e) {throw new RuntimeException("反序列化异常",e);}}
  • 写个Test测试一下能否序列化成功,使用Junit测试框架:
    写个public void函数,可以直接运行。
@Testpublic void test() throws JsonProcessingException {Article a =new Article();a.setId(001);a.setTitle("hello world");a.setContent("content");a.setCreateTime(new Date());a.setUser_id(2);String json=MAPPER.writeValueAsString(a);System.out.println(json);}

将Java对象转为json字符串,序列化成功
在这里插入图片描述

2.开发前后端接口

这一部分就是基于ajax的前后端分离式开发。开发流程:

  • 前端发送ajax请求;
  • 后端解析请求;
  • 服务端返回响应(json格式)
  • 客户端解析响应

在开发前需要思考的问题是:前端的入口是什么?后端需要的数据是什么?请求的格式及字段、响应的格式及字段。

(1)登录功能接口设计

在这里插入图片描述

业务分析:后端需要验证账号和密码,那么前端就需要提供账号密码。前端请求方式:POST;后端需要验证结果,来判断登录成功与否,登录成功跳转详情页,登录失败则给提示。最终形成两个文件,一个为前端设计,另一个是后端设计:
在这里插入图片描述
在这里插入图片描述

  • 前端ajax发送请求和解析服务器响应:
//发送ajax请求ajax({method:"POST",url:"login",//注意不要加/contantType:"application/json",body:JSON.stringify({//body里必须是json对象username:username.value,//前边的是json数据、请求数据的键;后边的是dom元素,为账号的值password:password.value,}),callback:function(status,responseText){//var json=handleResponse(status,responseText);if(!json)return;//解析响应正文//登录成功:调转到博客列表页面if(json.ok){location.href="blog_list.html";}else{alert(json.error);//error.innerHTML=json.error; }}})
  • 后端接收到请求解析验证和发出响应
    注:构造了一个Map类型的响应
@WebServlet("/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//处理请求resp.setCharacterEncoding("UTF-8");//将前端传过来的request json字符串转Java对象User user= WebUtil.deserialize(req, User.class);//构造一个返回数据Map<String,Object> body=new HashMap<>();//验证账号密码User query= UserDao.queryByUsername(user.getUsername());if(query==null){body.put("ok",false);body.put("error","账号不存在");}else if(!query.getPassword().equals(user.getPassword())){body.put("ok",false);body.put("error","账号或密码错误");}else {body.put("ok", true);//登录成功,创建sessionHttpSession session = req.getSession();session.setAttribute("user", query);}//返回响应WebUtil.serialize(resp,body);}
}
  • 另外,对帐号密码的验证会另外封装起来实现:
    即连接数据库,并从数据库中查询(按照用户名查询),验证用户是否存在,如果存在返回user,不存在时返回null
public static User queryByUsername(String username){Connection c=null;PreparedStatement ps=null;ResultSet rs=null;try{//1创建数据库连接c= DButil.getConnection();String sql="select * from user where username=?";//2创建命令对象ps=c.prepareStatement(sql);//替换占位符:第一个参数是占位符索引ps.setString(1,username);//3执行sqlrs=ps.executeQuery();//4处理结果集while (rs.next()){User user=new User();user.setId(rs.getInt("id"));user.setUsername(username);user.setPassword(rs.getString("password"));user.setNickname(rs.getString("nickname"));user.setHead(rs.getString("head"));user.setGithub(rs.getString("github"));return user;}return null;}catch (SQLException e) {throw new RuntimeException("根据账号查询用户出错",e);}finally {DButil.close((com.mysql.jdbc.Connection) c, (com.mysql.jdbc.Statement) ps,rs);}}

(2)博客列表显示

在这里插入图片描述

业务分析:这一部分是登录成功后进入的第一个界面,需要显示博客列表和用户信息。需要实现的功能是展示用户个人信息及博客列表信息。对其中的用户相关数据,不需要再次请求,因为登录后就会在session里保存用户信息。对于博客信息,设计为登陆后只能看到自己发布的文章。综上所述,需要设计两个接口,一个用户信息接口,一个博客列表接口。

  • 用户信息接口
    前端:在页面初始化时就发送ajax请求来获取数据。
    后端:从session中获取用户信息。
  • 博客列表接口
    前端:页面初始化时发送ajax请求获得文章列表;
    后端:初始化时就获取session中用户关联的文章列表

ajax请求及对服务器响应的解析和页面信息填充:

ajax({method:"get",url:"getUserInfo",callback:function(status,responseText){//var json=handleResponse(status,responseText);if(!json)return;//解析响应正文//昵称是设置标签内容if(json.nickname){nickname.innerHTML=json.nickname;}if(json.head){head.src=json.head;}if(json.github){github.href=json.github;}// var nickname=json.nickname;// var github=json.github;// var head=json.head;}});//获取文章列表信息ajax({method:"get",url:"blog/list",callback:function(status,responseText){var json=handleResponse(status,responseText);if(!json)return;//处理响应--解析响应正文Json,遍历文章列表//获取文章列表的父容器var blogListDiv=document.querySelector(".container-right");var str='';for(var i=0;i<json.length;i++){var article =json[i];var desc=article.content.length>50?article.content.substring(0,50):article.content;str+=`<div class="row"><div class="title">${article.title}</div><div class="date">${article.createTime}</div><div class="desc">${desc}</div><div class="to-detail"><a href="blog_content.html?id=${article.id}">查看全文 >></a></div></div>`}blogListDiv.innerHTML=str; }});

后端对请求的响应:

@WebServlet("/blog/list")
public class BlogListServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setCharacterEncoding("UTF-8");//获取session用户User user= WebUtil.validateLogin(req);//没有登录返回401if(user==null){resp.setStatus(401);return;}//登录。。查询文章列表//没有请求数据,但要根据用户查询获取文章List<Article> articles= ArticleDao.queryBlogList(user.getId());WebUtil.serialize(resp,articles);}
}

其中,对文章列表的获取会另外封装起来,即从数据库中根据用户查询文章:

public static List<Article> queryBlogList(Integer userId) {Connection c = null;PreparedStatement ps = null;ResultSet rs = null;try {//1.获取连接c = DButil.getConnection();String sql = "select *from article where user_id=?";//2.创建操作命令对象ps = c.prepareStatement(sql);//替换占位符ps.setInt(1, userId);//3执行sqlrs = ps.executeQuery();//4处理结果集List<Article> articles = new ArrayList<>();while (rs.next()) {Article a = new Article();a.setId(rs.getInt("id"));a.setTitle(rs.getString("title"));a.setContent(rs.getString("content"));java.sql.Timestamp createtime = rs.getTimestamp("create_time");a.setCreateTime(new java.util.Date(createtime.getTime()));a.setUser_id(userId);articles.add(a);}return articles;} catch (Exception e) {throw new RuntimeException("查询模块列表出错", e);} finally {DButil.close((com.mysql.jdbc.Connection) c, (Statement) ps, rs);}}

(3)博客详情页接口设计

在这里插入图片描述
业务分析:这一部分需要做的是:获取用户信息及获取文章详情信息。

  • 前端ajax请求
    包括发起用户信息的请求和文章详情的请求。发出请求时,url会带上文章Id以便后端查询。
    同时对返回服务端的响应作出解析填充到页面中。
<script>
//获取用户信息//需要设置的用户信息:先获取dom元素var nickname=document.querySelector("#nickname");var head=document.querySelector("#head");var github=document.querySelector("#github");ajax({method:"get",url:"getUserInfo",callback:function(status,responseText){//var json=handleResponse(status,responseText);if(!json)return;//解析响应正文//昵称是设置标签内容if(json.nickname){nickname.innerHTML=json.nickname;}if(json.head){head.src=json.head;}if(json.github){github.href=json.github;}// var nickname=json.nickname;// var github=json.github;// var head=json.head;}});//获取文章详情信息ajax({method:"get",url:"blog/detail"+location.search,callback:function(status,responseText){var json=handleResponse(status,responseText);if(!json)return;//处理响应--解析响应正文Json,遍历文章列表//获取文章列表的父容器var blogListDiv=document.querySelector(".container-right");var str='';str=`<div class="row"><div class="title">${json.title}</div><div class="date">${json.createTime}</div><div id="content" class="desc" style="background-color">${json.content}</div>                    </div>`               blogListDiv.innerHTML=str; //将ID为content的dom元素,标签内容,渲染md源码//editormd是引入的MarkdownJS库的一个对象editormad.markdownToHTML("content",{markdown:json.content})}    });
</script>
  • 后端响应
@WebServlet("/blog/detail")
public class BlogDetailServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setCharacterEncoding("UTF-8");String id=req.getParameter("id");Article a= ArticleDao.queryBlogDetail(Integer.parseInt(id));WebUtil.serialize(resp,a);}
}

(4)发布博客接口设计

业务分析:实现博客撰写和上传功能,具体操作为点击发布文章按钮,验证标题和内容,验证通过就提交文章数据。

  • 前端请求:
//绑定文章发布事件。。。//获取标题和内容的dom元素var title=document.querySelector("input");var content=document.querySelector("textarea");function articleAdd(){if(!title.value){alert("标题不能为空");return;}if(!content.value){alert("文章内容不能为空");return;}// 验证通过发请求:提交标题和内容到后端做插入文章顺序ajax({method:"post",url:"blog/add",contentType:"application/json",body:JSON.stringify({title:title.value,content:content.value,}),callback:function(status,responseText){var json=handleResponse(status,responseText);if(!json)return;if(json.ok){alert("提交成功!");location.href="blog_list.html";}}})}
  • 后端响应:
@WebServlet("/blog/add")
public class BlogAddServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setCharacterEncoding("utf-8");Article a= WebUtil.deserialize(req,Article.class);//获取session中的用户信息User user= WebUtil.validateLogin(req);//没有登录返回401if(user==null){resp.setStatus(401);return;}//登录,插入文章a.setUser_id(user.getId());int n= ArticleDao.insert(a);Map<String,Object> map=new HashMap<>();map.put("ok",true);WebUtil.serialize(resp,map);}
}

(5)注销功能接口

注销功能的实现:在实现这个功能时,只需要约定前后端交互接口。因为客户端代码不需要调整。注销按钮本来就是一个 < a href=“logout”> , 点击的时候就会发送 GET /logou 这样的请求。因此只需要在服务端实现:让session失效并重定向到登录页面即可。

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//注销功能resp.setCharacterEncoding("UTF-8");HttpSession session=req.getSession(false);if(session!=null){session.invalidate();}//重定向到登录页面resp.sendRedirect("login.html");}
}

技术难点

1.session和cookie会话管理
2.双重校验锁
3.Jackson序列化
4.junit测试
5.servlet
6.JDBC


http://chatgpt.dhexx.cn/article/3pqooa77.shtml

相关文章

javaweb实现个人博客系统

JAVAweb项目——个人博客系统 技术路线&#xff1a; 项目主要采用jsphtml前台页面&#xff0c;后端服务器采用servlet&#xff0c;编辑相关样式以及函数功能的时候使用到了bootstap和jQuery。数据库操作通过dbutils和c3p0连接池实现。Md编辑通过第三方插件editor.md实现。 实现…

一个简单漂亮的Java博客系统

预览地址&#xff1a;http://forestblog.liuyanzhao.com 关于项目 该博客是基于SSM实现的一个个人博客系统&#xff0c;适合初学SSM和个人博客制作的同学学习。 主要涉及技术包括的包括 Maven、Spring、SpringMVC、MyBatis、JSP等 最新写了一篇该项目的毕业设计论文&#xf…

Java程序员博客系统推荐!我调研了100来个 Java 开源博客系统,发现这 5 个最好用!

最近想倒腾一下博客&#xff0c;看了很多现成的比较成熟的开源博客系统&#xff0c;自己也简单从下面几个维度总结对比了一下&#xff1a; star数量技术选型社区生态 当然啦&#xff01;好东西不能独享。下面简单分享一下我所做的笔记。 欢迎小伙伴们评论区补充完善。ღ( &a…

JavaWeb搭建简易个人博客

前台首页访问路径&#xff1a;/index.jsp 后台访问路径:/admin.jsp 运行项目前请把blog-parent目录下的database.sql加载到数据库中,并在blog-web/资源文件夹下的db.properties里配置数据库访问账号和密码 CSDN下载链接:点击链接下载

Java项目-Javaweb实现个人博客

作者主页&#xff1a;编程指南针 简介&#xff1a;Java领域优质创作者、CSDN博客专家 Java项目、简历模板、学习资料、面试题库、技术互助 文末获取源码 项目编号 &#xff1a;KS020 运行环境&#xff1a; 开发工具&#xff1a;IDEA /ECLIPSE 应用服务器&#xff1a;TOMCA…

用java写一个博客网站

可以先看一下这个网站长怎么样&#xff0c;哈哈哈&#xff0c;小屋知多少 先说一下这个博客有哪写功能&#xff1f;然后这个是代码后台下载地址&#xff1a;https://gitee.com/c-xiaobai-c/ssm-blog-website-background.git 前台下载地址&#xff1a;https://gitee.com/c-xia…

JavaWeb项目 -- 博客系统

JavaWeb项目 -- 博客系统 前言&#xff1a;页面展示一、创建 Maven 项目二、设计数据库三、封装数据库的操作3.1 创建 DBUtil 类3.2 创建 Blog 类3.3 创建 User 类3.4 创建类 BlogDao3.5 创建类 UserDao 四、导入准备好的前端代码五、实现博客列表界面5.1 约定好前后端交互接口…

【Java项目】从0到1构建一个博客系统

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaWeb】 ✈️✈️本篇内容:从0到1构建一个博客系统&#xff01; &#x1f680;&#x1f680;代码托管平台github&#xff1a;博客系统源码托管&#xff01; ⛵…

史上最全的 Java 高质量博客与网站推荐(国内篇)

阅读文本大概需要 6.66 分钟。 前言 我最近在系统整理一些 Java 后台方面的面试题和参考答案&#xff0c;有找工作需求的童鞋&#xff0c;欢迎关注我的 Github 仓库&#xff0c;如果觉得不错可以点个 star 关注 &#xff1a; 1、awesome-java-interview2、awesome-java-notes…

博客系统[Java]

目录 一.准备工作 二.实现数据库代码(JDBC) 1.创建数据库/表结构>数据库设计 2.封装数据库(Model) 1>创建DBtil封装数据库连接操作 2>创建实体类-->表示一条记录 3>封装针对数据的增删改查 三.博客列表页 1.约定前后端 2.编写服务器代码 3.编写客户端…

JavaWeb项目—— 博客系统

文章目录 效果展示1. 创建 maven 项目2. 设计数据库3. 封装数据库的操作代码3.1 创建 DBUtil 类3.2 创建 Blog&#xff08;代表一篇博客&#xff09;3.3 创建 User&#xff08;代表一个用户&#xff09;3.4 创建类 BlogDao&#xff08;对博客表进行操作&#xff09;3.5 创建类 …

Java个人博客项目

目录 引言 开发环境 所用技术 项目目录 数据库设计 功能介绍 源码下载 更多优质练手项目 Java学生成绩管理系统 JavaWeb练手项目ATM机 Java图书管理系统 Java电子发票管理系统 引言 这个项目是大二下学期期末考核项目&#xff0c;当时是自选主题写一个项目&#x…

Java项目——个人博客系统

文章目录 一、项目背景二、项目功能三、项目的基本流程1.准备工作2.数据库设计3.准备前端页面4.实现前端匹配的Servlet所需功能5.项目难点 一、项目背景 在学习完JavaWeb相关知识后&#xff0c;有了基础能力就想通过完成一个Javaweb项目来回顾和加强已经学过的知识&#xff0c…

【Java】博客系统——详细解释+代码+详细注释(课设必过)

目录 前言 博客系统简要分析 一、数据库的设计 1.1 分析 1.2 代码实现&#xff08;创建数据库和表&#xff09; 二、封装数据库&#xff08;JDBC代码的编写&#xff09; 2.1、首先通过创建Maven项目&#xff0c;基于Small Tomcat部署 servlet&#xff1b; 2.2、封装数据…

SSM分布式框架搭建

现在我们看一下我们大家的项目的结构&#xff1a; 一、建立框架&#xff1a; 二、建立root File –》 New –》Module 三、建立子项目tool File–》New –》Module 以同样的方式建立base-manage项目&#xff0c;他的子项目选择org.apache.maven.archetypes:maven-archetype…

8.分布式爬虫框架

目录 分布式爬虫框架消息队列Redis和Scrapy-Redis 分布式爬虫框架 分布式爬虫框架分为两种&#xff1a;控制模式&#xff08;左&#xff09;和自由模式&#xff08;右&#xff09;&#xff1a; 控制模式中的控制节点是系统实现中的瓶颈&#xff0c;自由模式则面临爬行节点之间…

golang 分布式框架Origin学习笔记

最近项目的后端需求是全球同服的&#xff0c;在使用语言方面确定了为golang之后&#xff0c;了解了一下当前的一些goalng游戏服务器框架&#xff0c;终于在leaf/pitaya/ 等众多框架中选择了 Origin&#xff0c; 主要是因为它是分布式框架&#xff0c;微服务架构&#xff0c;比较…

Java开发Dubbo分布式框架

引言 Dubbo是一个分布式服务框架&#xff0c;致力于提供高性能和透明化的RPC远程服务调用方案&#xff0c;以及SOA服务治理方案。简单的说&#xff0c;dubbo就是个服务框架&#xff0c;如果没有分布式的需求&#xff0c;其实是不需要用的&#xff0c;只有在分布式的时候&#x…

PyTorch 分布式框架 Ray :保姆级入门教程

来源&#xff1a;官方博客 翻译&#xff1a;PyTorch 开发者社区&#xff08;微信公众号&#xff09; 今天的机器学习需要分布式计算。无论是训练网络、调整超参数、服务模型还是处理数据&#xff0c;机器学习都是计算密集型的&#xff0c;如果没有访问集群&#xff0c;速度会非…

celery 分布式框架详解

Celery 结构图 如果没有celery&#xff0c;让你自己设计一个异步任务队列你怎么做。 首先&#xff0c;要有一个发起任务的client&#xff0c;选定一定保存任务信息的媒介&#xff0c;由一个worker去一直监听这个信息媒介&#xff0c;这个worker最好是多进程的&#xff0c;另外…