1. 项目简介
1.1 项目背景
在网络学完HTTP协议,前端学完html,css,js,后端学完Servlet开发后,做一个博客系统,巩固一下所学知识,并将所学知识运用到实际当中,以此来进一步提升对学习编程的兴趣
1.2 项目用到的技术
前端使用到html,css,js,使用ajax技术发送http请求,请求body的格式为json格式
后端使用Servlet进行开发
使用Mysql数据库保存数据
除此还引入了editor.md,editor.md是一个开源的页面markdown编辑器组件
采用Maven构建工具搭建项目开发环境
1.3 项目功能简单介绍
登陆页面:输入用户及密码,点击提交,如果用户或密码错误,会提示用户或密码错误,账号及密码正确则登陆成功,成功后跳转到博客列表页面
博客列表页面:博客列表页面展示所有发布过的文章,文章显示最多显示50字,如果想查看全文,则需要点击文章下的显示全文
博客详情页面:点击某篇文章的显示全文按钮,则会展示文章的全部内容
博客编辑页面:点击博客列表的写博客,会跳转到博客编辑页面,输入文章题目及文章内容点击发布文章,文章即可发布成功,发布成功后会跳转到博客列表页面,可以查看发布过的文章
博客注销按钮:点击博客注销按钮,则会跳转到博客登陆页面
2. 页面及功能展示
登陆页面
输入用户和密码,点击提交,登陆成功后跳转到博客列表页面
点击写博客,跳转到博客编辑页面
输入文章标题和文章内容,点击发布文章,发布成功后跳转到博客列表页面
在博客列表页面,点击刚发布文章的显示全文,就会显示刚才发布文章的全部内容
点击注销又跳转到博客登陆页面
3. 博客系统页面设计
这里附上静态页面设计的码云地址,可以点击查看,本篇文章只展示后端代码与前端ajax交互的部分,想要查看博客系统页面设计代码,请点击:个人博客系统的页面设计代码
4. 项目准备工作
创建Maven项目在pom.xml中添加项目依赖
后端采用Servlet开发
数据库使用Mysql
jackson框架可以进行序列化和反序列化,将java对象和json字符串相互转化
junit框架提供单元测试
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>my-blog</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> <!-- 单元测试框架 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> </dependency> </dependencies> <build> <finalName>my-blog</finalName> </build> </project>
创建与开发相关的包
引入前端资源
将前端资源都放在main/webapp目录下,前端资源从上面码云地址中获取,web.xml存放在main/webapp/WEB-INF目录下
5. 博客系统功能设计
5.1 设计数据库表
有用户登陆,所以有一张用户表,观察博客列表有显示用户昵称,所以用户表设计有四个字段:用户id,用户名,密码,昵称
有文章展示,所以有一张文章表,文章有文章id,标题,发布时间,文章内容,关联用户的外键
一个用户可以发布多篇文章,所以用户与文章对应关系为1:m,用户id作为文章表的外键
创建表的时候可以插入一些数据便于后续的测试
drop database if exists blog; create database blog character set utf8mb4; use blog; create table user( id int primary key auto_increment, username varchar(20) not null unique, password varchar(20) not null, nickname varchar(10) not null ); insert into user values(null,'abc','123','糯米'); create table article( id int primary key auto_increment, title varchar(50) not null, `date` date, content mediumtext, user_id int, foreign key (user_id) references user(id) ); insert into article values(null,'文章1','2022-9-9','今天要好好学习',1); insert into article values(null,'文章2','2022-9-17','今天要玩游戏',1);
5.2 工具类util
1. 创建数据库工具类DBUtil,提供获取数据库连接和统一释放资源
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; //数据库工具类,提供获取数据库连接,释放资源统一代码 public class DBUtil { //一个程序,连接一个数据库,只需要一个连接池,其中保存了多个数据库连接对象 private static MysqlDataSource ds; //静态变量,类加载时执行初始化,只执行一次 //获取连接池,内部使用,不开放 private static DataSource getDataSource(){ if(ds == null){ ds = new MysqlDataSource(); ds.setURL("jdbc:mysql://127.0.0.1:3306/blog"); ds.setUser("root"); ds.setPassword("xiaobai520..@@@"); ds.setUseSSL(false); //不安全连接,不设置会有警告 ds.setCharacterEncoding("UTF-8"); } return ds; } //获取数据库连接对象,开放给外部的jdbc代码使用 public static Connection getConnection(){ try { return getDataSource().getConnection(); } catch (SQLException e) { throw new RuntimeException("获取数据库连接报错",e); } } //释放资源,查询操作需要释放三个资源 public static void close(Connection c, Statement s, ResultSet rs){ try { if(rs != null) rs.close(); if(s != null) s.close(); if(c != null) c.close(); } catch (SQLException e) { throw new RuntimeException("释放数据库资源出错",e); } } //更新操作释放两个资源 public static void close(Connection c,Statement s){ close(c,s,null); } }
2. 创建Web工具类WebUtil,提供一个类专门检查用户是否登陆,还提供序列化与反序列化类,用来将java对象与json字符串相互转化
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.example.model.User; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.InputStream; public class WebUtil { public static User checkLogin(HttpServletRequest req){ User user = null; HttpSession session = req.getSession(false); user = (User) session.getAttribute("user"); return user; } //使用单例 private static ObjectMapper mapper = new ObjectMapper(); //反序列化:json字符串转换Java对象 //使用泛型,传一个什么类型,就返回该类型的对象 //泛型方法:方法限定符 <类型型参列表> 返回值类型 方法名 public static <T> T read(InputStream is,Class<T> clazz){ try { return mapper.readValue(is,clazz); } catch (IOException e) { throw new RuntimeException("json反序列化出错",e); } } //序列化:将java对象转化为json字符串 public static String write(Object o){ try { return mapper.writeValueAsString(o); } catch (JsonProcessingException e) { throw new RuntimeException("json序列化出错",e); } } }
5.3 实体类model
每张用户表对应有一个实体类,所以创建User和Article类,创建类的时候提供Getter和Setter方法并且重写toString方法
用户类User
public class User { private Integer id; private String username; private String password; private String nickname; @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", nickname='" + nickname + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } 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; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } }
文章类Article
import java.util.Date; public class Article { private Integer id; private String title; private Date date; //时间 private String content; private Integer userId; private String dateString;//日期字符串 @Override public String toString() { return "Article{" + "id=" + id + ", title='" + title + '\'' + ", date=" + date + ", content='" + content + '\'' + ", userId=" + userId + ", dateString='" + dateString + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getDateString() { return dateString; } public void setDateString(String dateString) { this.dateString = dateString; } }
Java对象JsonResult类
后端返回给前端的响应时返回的是json字符串,所以需要一个JsonResult类,该类的字段保存操作是否成功和要返回给前端的数据,后端在返回给前端json字符串的时候只需要将该类序列化为json字符串返回给前端,该类也得提供Getter与Setter方法并且重写toString方法
public class JsonResult { private boolean ok;//标识执行一个操作是否成功 private Object data;//操作成功,且是一个查询操作,需要返回一些数据给前端 @Override public String toString() { return "JsonResult{" + "ok=" + ok + ", data=" + data + '}'; } public boolean isOk() { return ok; } public void setOk(boolean ok) { this.ok = ok; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
5.4 前后端业务处理
前后端业务逻辑的实现顺序:
先在前端构造ajax请求
再做后端业务逻辑
最后再前端才设置回调函数执行回调
说明:后面实现的顺序是先前端再后端,但是观看参考时,建议按照上面的逻辑顺序,因为实际开发时就是按照这个顺序来开发的
5.4.1 登陆页面功能设计
所有的请求都是使用ajax发送http请求,所以将封装的ajax函数写在一个js文件中,后续发送请求时只需将封装的ajax函数引入即可
封装的ajax函数
//封装ajax函数,args为一个js对象 //args对象属性如下: //method:请求方法,url:请求资源路径,contenType:请求正文格式 //body:请求正文,callback:回调函数,客户端接收到响应数据后调用 function ajax(args) { let xhr = new XMLHttpRequest(); //设置回调函数 xhr.onreadystatechange = function () { //4:客户端接收到服务端响应 if (xhr.readyState == 4) { //回调函数可能会使用响应的内容,作为传入参数 args.callback(xhr.status, xhr.responseText); } } xhr.open(args.method, args.url); //如果args中contentType有内容,就设置Content-Type请求头 if (args.contentType) {//js中if可以判断是否有值 xhr.setRequestHeader("Content-Type", args.contentType); } //如果args中body有内容,设置body请求正文 if (args.body) { xhr.send(args.body); } else { xhr.send(); } }
前端设计
给登陆提交按钮绑定点击事件,获取到输入的用户名和密码后,发送ajax请求
请求方法为post,请求url为login,后端的Servlet路径也要与此对应,设置contentType为application/json,请求body为json字符串
json对象保存输入的用户名和密码,将json对象转化为json字符串设置到body中
设置回调函数,回调函数有两个参数,一个为响应状态码,一个为后端返回的响应为json字符串,后端返回的json字符串中保存操作是否成功字段
如果响应状态码为200,并且ok为true,则登陆成功,跳转到博客列表页面,如果ok为false则用户名或密码错误,如果响应状态码不为200,则提示响应状态码及响应body,以便程序员作出更改
<script src="js/util.js"></script> <script> let submit = document.querySelector("#submit"); //绑定提交按钮点击事件 submit.onclick = function(){ let username = document.querySelector("#username").value; let password = document.querySelector("#password").value; //发送ajax请求,需要设置method,url,contentType,body ajax({ method: "post", url: "login", contentType: "application/json", body: JSON.stringify({ //冒号前是前后端约定的键,冒号后是变量值 username: username, password: password }), callback: function(status,responseText){ if(status == 200){ let json = JSON.parse(responseText); if(json.ok){ alert("登陆成功"); window.location.href = "blog_list.html"; }else { alert("账号或密码错误"); } }else { alert("响应状态码:"+status+"/nbody:"+responseText); } } }); } </script>
后端Servlet设计
前端发送的body为json字符串
所以先使用InputStream输入流获取请求数据,将请求数据转化为user对象
使用该对象在数据库做校验,如果校验成功,设置session,设置要返回给前端的JsonResult对象json
设置完后,将json对象序列化json字符串后返回给前端
前端的回调函数就是依据后端返回的json字符串做相应的逻辑处理
@WebServlet("/login")//登陆 public class LoginServlet extends HttpServlet { //登陆功能,json提交{username:abc,password:123} @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //解析请求:通过输入流获取请求数据 req.setCharacterEncoding("utf-8"); //设置请求对象的编码格式 InputStream is = req.getInputStream(); //将输入流中的json字符串转化为java对象 //使用ObjectMapper将java对象和json字符串相互转换,Servlet都要用,封装到WebUtil中 User get = WebUtil.read(is,User.class); //在数据库校验账号密码:通过账号密码在数据库查用户,若能查到则账号密码正确 User user = UserDao.isLogin(get.getUsername(),get.getPassword()); //不管登陆是否成功,返回的http响应正文(body)都是json字符串 //需要设计一个类,这个类的成员变量属性,用于前端ajax解析响应 //先创建一个响应正文需要的Java对象,然后在转换为json字符串,再设置到响应正文 JsonResult json = new JsonResult(); if(user != null){ //登陆成功,设置session HttpSession session = req.getSession(true); session.setAttribute("user",user); //设置json对象中,操作是否成功为true json.setOk(true); }else { //登陆失败,设置操作是否成功字段为false json.setOk(false); } //设置响应正文的格式 resp.setContentType("application/json; charset=utf-8"); resp.getWriter().write(WebUtil.write(json)); } }
5.4.2 博客列表页面功能设计
前端设计
客户端展示页面时,就需要展示文章列表数据,加载完页面就发生ajax请求,来获取文章列表内容,待收到返回的响应执行回调时,解析响应的文章列表数据
发送的ajax请求,method为get,url为blog_list,对应的后端Servlet路径也要与之对应
因为是get请求,所以没有body
设置回调函数,与前面登陆的回调函数逻辑相似,将后端返回的json字符串转化为json对象时,如果ok为true,则解析返回的数据
将返回的nickname和文章数设置到前端,将返回的文章集合以循环的方式设置到前端
<script src="js/util.js"></script> <script> //客户端展示页面时,就需要展示文章列表数据 //加载完页面,就发送ajax请求获取文章列表的数据 //返回响应执行回调时,解析响应的文章列表数据 ajax({ method: "get", url: "blog_list", callback: function(status,responseText){ if(status == 200){ let json = JSON.parse(responseText); if(json.ok){ let data = json.data; let nickname = data.nickname; let h3 = document.querySelector(".card>h3"); h3.innerHTML = nickname; let articles = data.articles; let div = document.querySelector(".container-right"); //str不赋值就是undefined,再去拼接字符串就会出错 let str = ""; for(let a of articles){ //``里面可以包括单引号和双引号 str += `<div class="row">`; str += `<div class="title">`; str += a.title; str += `</div>`; str += `<div class="date">`; str += a.dateString; str += `</div>`; str += `<div class="desc">`; str += `<p>`; str += a.content; str += `</p>`; str += `</div>`; str += `<div class="to-detail">`; str += `<a href="blog_content.html?id=` + a.id; str += `">显示全文>></a>`; str += `</div>`; str += `</div>`; } div.innerHTML = str; let num = data.count; let count = document.querySelector("#count"); count.innerHTML = num; }else { alert("ok==false"); } }else { alert("响应状态码:"+status+"/nbody:"+responseText) } } }); </script> </html>
后端Servlet设计
先校验用户是否登陆,未登录不允许访问,直接跳转到用户登陆页面,登陆后才可执行后边逻辑
登陆成功后用用户的id查询该用户的所有文章并且查询该用户的所有文章数目
此时已经登陆成功,设置JsonResult对象json的ok为true
创建一个Map结构的data,保存要返回给前端的数据文章列表和用户昵称和文章数目
将data设置到json对象中,将json对象序列化为json字符串返回给前端
@WebServlet("/blog_list")//博客列表 public class BlogListServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //未登录,访问跳转到登陆页面 User user = WebUtil.checkLogin(req); if(user == null){ resp.sendRedirect("login.html"); return; //未登录,直接跳转,不会执行后边逻辑 } //通过登陆用户id查找所有文章 List<Article> articles = ArticleDao.selectById(user.getId()); //通过登陆用户id查找文章数目 int count = ArticleDao.getCount(user.getId()); //先构造响应正文需要的java对象,再转化为json字符串,再设置到响应正文 JsonResult json = new JsonResult(); json.setOk(true); //前端需要的数据有nickname,articles,可以用map保存,然后设置到json.data中 Map<String,Object> data = new HashMap<>(); data.put("nickname",user.getNickname()); data.put("articles",articles); data.put("count",count); json.setData(data); resp.setContentType("application/json; charset=utf-8"); resp.getWriter().write(WebUtil.write(json)); } } let article = data.article;
5.4.3 博客详情页面功能设计
前端设计 博客详情是从博客列表的显示全文按钮跳转过来的,所以跳转的连接携带id,id标识文章id,表示显示的是哪篇文章的全部内容 先使用window.location.search.substring获取到文章id 再发送ajax请求,请求方法为get,请求url为blog_content?id=id,设置回调函数 待后端返回响应后执行回调函数,将响应正文转化为json对象,解析json对象 设置用户昵称,文章数目,文章标题,发表日期,文章内容 <script src="js/util.js"></script> <script> //window.location.search获取的是queryString?后的部分,blog_content?id=1 //也就是获取的是?id=1 let id = window.location.search.substring(4); //页面一加载就需要展示博客详情页面,所以就发送ajax请求来获取内容 ajax({ method: "get", url: "blog_content?id="+id, callback: function(status,responseText){ if(status == 200){ let json = JSON.parse(responseText); if(json.ok){ let data = json.data; let nickname = data.nickname; let h3 = document.querySelector(".card>h3"); h3.innerHTML = nickname; let num = data.count; let count = document.querySelector("#count"); count.innerHTML = num;let div = document.querySelector(".detail"); let str = ""; str += `<div class="title">`; str += article.title; str += `</div>`; str += `<div class="date">`; str += article.dateString; str += `</div>`; str += `<div id="article-content" class="desc">`; //str += article.content; str += `</div>`; div.innerHTML = str; //不能直接展示markdown源码,数据库保存的是markdown源码 editormd.markdownToHTML("article-content",{markdown: article.content}); }else { alert("ok == false"); } }else { alert("响应状态码:"+status+"/nbody:"+responseText); } } }); </script>
后端Servlet设计
用户未登录不允许访问,直接跳转到用户登陆页面
请求数据携带在queryString中,所以使用req.getParameter解析请求获取到文章id
根据文章id查询整个文章将查询的数据设置到一个文章对象中
将JsonResult对象json的ok设置为true
使用一个Map结构data保存获取的文章数目,文章,用户昵称
将data设置到json对象中,将json对象序列化为json字符串后返回给前端
@WebServlet("/blog_content")//博客详情 public class BlogContentServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //未登录,访问跳转到登陆页面 User user = WebUtil.checkLogin(req); if(user == null){ resp.sendRedirect("login.html"); return; //未登录,直接跳转,不会执行后边逻辑 } //路径为:blog_content?id=文章id //解析请求 String sid = req.getParameter("id"); //获取到文章id //通过文章id查询整篇文章 Article a = ArticleDao.queryById(Integer.parseInt(sid)); int count = ArticleDao.getCount(user.getId()); JsonResult json = new JsonResult(); json.setOk(true); Map<String,Object> data = new HashMap<>(); data.put("nickname",user.getNickname()); data.put("article",a); data.put("count",count); json.setData(data); resp.setContentType("application/json; charset=utf-8"); resp.getWriter().write(WebUtil.write(json)); } }
5.4.4 博客编辑页面功能设计
前端设计
给发布文章绑定点击事件,点击发布,发送ajax请求用于给文章表中添加数据
获取到输入的文章标题和文章内容,将其设置为json对象
发送ajax请求的方法为post,url为blog_add,后端Servlet路径要与之对应,设置contentType为application/json,将设置的json对象转化为json字符串设置到body中
待收到后端返回的响应后,执行回调,提示发布文章成功并且跳转到博客列表页面
<script src="js/util.js"></script> <script src="js/jquery.min.js"></script> <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> <script> $(function(){ var editor = editormd("edit-content",{ width: "100%", height: "calc(100% - 50px)", markdown: "# 在这里写下第一篇博客", path: "editor.md/lib/", saveHTMLToTextarea: true }); }) //发布文章点击事件 function addContent(){ let title = document.querySelector("#title").value; let content = document.querySelector("#content").value; ajax({ method: "post", url: "blog_add", contentType: "application/json", body: JSON.stringify({ title: title, content: content }), callback: function(status,responseText){ if(status == 200){ let json = JSON.parse(responseText); if(json.ok){ alert("发布文章成功"); window.location.href = "blog_list.html"; }else { alert("ok == false"); } }else { alert("响应状态码:"+status+"/nbody:"+responseText); } } }); } </script>
后端Servlet设计
用户未登录不允许访问,直接跳转到用户登录页面
使用InputStream解析请求,通过输入流获取数据
将输入流中的json字符串转化为文章对象
设置用户id,发布日期到该文章对象中
将JsonResult对象json的ok设置为true,将json对象序列化为json字符串后返回给前端
@WebServlet("/blog_add")//添加文章 public class BlogAddServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { User user = WebUtil.checkLogin(req); if(user == null){ //未登录不允许访问 resp.sendRedirect("login.html"); return; } //解析请求 req.setCharacterEncoding("utf-8"); InputStream is = req.getInputStream(); Article beInsert = WebUtil.read(is,Article.class); //数据库插入一条数据,相当于插入一个对象 beInsert.setUserId(user.getId()); beInsert.setDate(new java.util.Date()); int n = ArticleDao.insertOne(beInsert); JsonResult json = new JsonResult(); json.setOk(true); resp.setContentType("application/json; charset=utf-8"); resp.getWriter().write(WebUtil.write(json)); } }
5.4.5 用户注销功能设计
获取到session
如果session不为空,将session中保存的user删除
删除后跳转到用户登陆页面
@WebServlet("/logout") public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //注销就是通过session对象删除保存的用户信息 HttpSession session = req.getSession(false); if(session != null){ session.removeAttribute("user"); } resp.sendRedirect("login.html"); } }
6. 数据库逻辑处理
前端后端做业务处理的数据库逻辑操作如下:
6.1 用户表的逻辑处理
通过登陆输入的用户名和密码查询到user并将user返回,以此来做用户密码校验功能
public class UserDao { public static User isLogin(String username, String password){ Connection c = null; PreparedStatement ps = null; ResultSet rs = null; try { c = DBUtil.getConnection(); String sql = "select * from user where username=? and password=?"; ps = c.prepareStatement(sql); ps.setString(1,username); ps.setString(2,password); rs = ps.executeQuery(); User user = null; while(rs.next()){ user = new User(); int id = rs.getInt("id"); String nickname = rs.getString("nickname"); user.setId(id); user.setNickname(nickname); user.setUsername(username); user.setPassword(password); } return user; } catch (SQLException e) { throw new RuntimeException("校验账号密码出错",e); } finally { DBUtil.close(c,ps,rs); } } @Test public void testLogin(){ System.out.println(isLogin("abc","123")); } }
6.2 文章表的逻辑处理
通过用户id查询所有文章
//通过用户id查询所有文章 public static List<Article> selectById(Integer id){ List<Article> articles = new ArrayList<>(); Connection c = null; PreparedStatement ps = null; ResultSet rs = null; try{ c = DBUtil.getConnection(); String sql = "select * from article where user_id=?"; ps = c.prepareStatement(sql); ps.setInt(1,id); rs = ps.executeQuery(); while(rs.next()){ Article a = new Article(); a.setId(rs.getInt("id")); a.setTitle(rs.getString("title")); java.sql.Date date = rs.getDate("date"); long time = date.getTime(); a.setDate(new java.util.Date(time)); DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); String dateString = df.format(a.getDate()); a.setDateString(dateString); String content = rs.getString("content"); a.setContent(content.length()>50 ? content.substring(0,50) : content); a.setUserId(id); articles.add(a); } return articles; } catch (SQLException e) { throw new RuntimeException("查询文章出错",e); } finally { DBUtil.close(c,ps,rs); } } 根据文章id查询整篇文章 //根据文章id查文章 public static Article queryById(int id) { Article a = null; Connection c = null; PreparedStatement ps = null; ResultSet rs = null; try{ c = DBUtil.getConnection(); String sql = "select * from article where id=?"; ps = c.prepareStatement(sql); ps.setInt(1,id); rs = ps.executeQuery(); while(rs.next()){ a = new Article(); a.setId(id); a.setTitle(rs.getString("title")); java.sql.Date date = rs.getDate("date"); DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); String dateString = df.format(new java.util.Date(date.getTime())); a.setDateString(dateString); a.setContent(rs.getString("content")); a.setUserId(rs.getInt("user_id")); } return a; } catch (SQLException throwables) { throw new RuntimeException("查询文章详情jdbc出错",throwables); } finally{ DBUtil.close(c,ps,rs); } }
插入一篇文章
//插入文章 public static int insertOne(Article a) { Connection c = null; PreparedStatement ps = null; try{ c = DBUtil.getConnection(); String sql = "insert into article(title,`date`,content,user_id) values(?,?,?,?)"; ps = c.prepareStatement(sql); ps.setString(1,a.getTitle()); //ps.setDate(2,new java.sql.Date(a.getDate().getTime())) ps.setDate(2,new java.sql.Date(System.currentTimeMillis())); ps.setString(3,a.getContent()); ps.setInt(4,a.getUserId()); return ps.executeUpdate(); } catch (SQLException throwables) { throw new RuntimeException("发布文章jdbc出错",throwables); } finally { DBUtil.close(c,ps); } }
获取文章数目
public static int getCount(Integer id) { Connection c = null; PreparedStatement ps = null; ResultSet rs = null; try{ c = DBUtil.getConnection(); String sql = "select 0 from article where user_id=?"; ps = c.prepareStatement(sql); ps.setInt(1,id); rs = ps.executeQuery(); int count = 0; while(rs.next()){ count++; } return count; } catch (SQLException throwables) { throw new RuntimeException("查询文章数目出错",throwables); } finally{ DBUtil.close(c,ps,rs); } }
7. 博客系统设计源码
在做前后端逻辑处理的时候,前端代码有些稍微的改动,本文没有提及到,请点击查看源码,查看改动的细节以及所有后端的设计实现:个人博客系统设计源码