• 【JavaWeb项目】博客系统


    目录

    1. 项目简介 

    1.1 项目背景

    1.2 项目用到的技术

    1.3 项目功能简单介绍 

    2. 页面及功能展示

    3. 静态页面设计 

    4. 项目准备工作

    5. 博客系统功能设计

    5.1 设计数据库表

    5.2 工具类util

    5.3 实体类model

    5.4 前后端业务处理 

    5.4.1 登陆页面功能设计 

    5.4.2 博客列表页面功能设计

    5.4.3 博客详情页面功能设计 

    5.4.4 博客编辑页面功能设计

    5.4.5 用户注销功能设计

    6. 数据库逻辑处理 

    6.1 用户表的逻辑处理

    6.2 文章表的逻辑处理 

    7. 博客系统设计源码


    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框架提供单元测试
    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0modelVersion>
    6. <groupId>org.examplegroupId>
    7. <artifactId>my-blogartifactId>
    8. <version>1.0-SNAPSHOTversion>
    9. <properties>
    10. <maven.compiler.source>8maven.compiler.source>
    11. <maven.compiler.target>8maven.compiler.target>
    12. properties>
    13. <dependencies>
    14. <dependency>
    15. <groupId>javax.servletgroupId>
    16. <artifactId>javax.servlet-apiartifactId>
    17. <version>3.1.0version>
    18. dependency>
    19. <dependency>
    20. <groupId>mysqlgroupId>
    21. <artifactId>mysql-connector-javaartifactId>
    22. <version>5.1.49version>
    23. dependency>
    24. <dependency>
    25. <groupId>com.fasterxml.jackson.coregroupId>
    26. <artifactId>jackson-databindartifactId>
    27. <version>2.12.3version>
    28. dependency>
    29. <dependency>
    30. <groupId>junitgroupId>
    31. <artifactId>junitartifactId>
    32. <version>4.13.1version>
    33. dependency>
    34. dependencies>
    35. <build>
    36. <finalName>my-blogfinalName>
    37. build>
    38. project>

    创建与开发相关的包

      

    引入前端资源 

    将前端资源都放在main/webapp目录下,前端资源从上面码云地址中获取,web.xml存放在main/webapp/WEB-INF目录下 

    5. 博客系统功能设计

    5.1 设计数据库表

    • 有用户登陆,所以有一张用户表,观察博客列表有显示用户昵称,所以用户表设计有四个字段:用户id,用户名,密码,昵称
    • 有文章展示,所以有一张文章表,文章有文章id,标题,发布时间,文章内容,关联用户的外键
    • 一个用户可以发布多篇文章,所以用户与文章对应关系为1:m,用户id作为文章表的外键 

    创建表的时候可以插入一些数据便于后续的测试

    1. drop database if exists blog;
    2. create database blog character set utf8mb4;
    3. use blog;
    4. create table user(
    5. id int primary key auto_increment,
    6. username varchar(20) not null unique,
    7. password varchar(20) not null,
    8. nickname varchar(10) not null
    9. );
    10. insert into user values(null,'abc','123','糯米');
    11. create table article(
    12. id int primary key auto_increment,
    13. title varchar(50) not null,
    14. `date` date,
    15. content mediumtext,
    16. user_id int,
    17. foreign key (user_id) references user(id)
    18. );
    19. insert into article values(null,'文章1','2022-9-9','今天要好好学习',1);
    20. insert into article values(null,'文章2','2022-9-17','今天要玩游戏',1);

    5.2 工具类util

    1. 创建数据库工具类DBUtil,提供获取数据库连接和统一释放资源

    1. import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
    2. import javax.sql.DataSource;
    3. import java.sql.Connection;
    4. import java.sql.ResultSet;
    5. import java.sql.SQLException;
    6. import java.sql.Statement;
    7. //数据库工具类,提供获取数据库连接,释放资源统一代码
    8. public class DBUtil {
    9. //一个程序,连接一个数据库,只需要一个连接池,其中保存了多个数据库连接对象
    10. private static MysqlDataSource ds; //静态变量,类加载时执行初始化,只执行一次
    11. //获取连接池,内部使用,不开放
    12. private static DataSource getDataSource(){
    13. if(ds == null){
    14. ds = new MysqlDataSource();
    15. ds.setURL("jdbc:mysql://127.0.0.1:3306/blog");
    16. ds.setUser("root");
    17. ds.setPassword("xiaobai520..@@@");
    18. ds.setUseSSL(false); //不安全连接,不设置会有警告
    19. ds.setCharacterEncoding("UTF-8");
    20. }
    21. return ds;
    22. }
    23. //获取数据库连接对象,开放给外部的jdbc代码使用
    24. public static Connection getConnection(){
    25. try {
    26. return getDataSource().getConnection();
    27. } catch (SQLException e) {
    28. throw new RuntimeException("获取数据库连接报错",e);
    29. }
    30. }
    31. //释放资源,查询操作需要释放三个资源
    32. public static void close(Connection c, Statement s, ResultSet rs){
    33. try {
    34. if(rs != null) rs.close();
    35. if(s != null) s.close();
    36. if(c != null) c.close();
    37. } catch (SQLException e) {
    38. throw new RuntimeException("释放数据库资源出错",e);
    39. }
    40. }
    41. //更新操作释放两个资源
    42. public static void close(Connection c,Statement s){
    43. close(c,s,null);
    44. }
    45. }

    2. 创建Web工具类WebUtil,提供一个类专门检查用户是否登陆,还提供序列化与反序列化类,用来将java对象与json字符串相互转化

    1. import com.fasterxml.jackson.core.JsonProcessingException;
    2. import com.fasterxml.jackson.databind.ObjectMapper;
    3. import org.example.model.User;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpSession;
    6. import java.io.IOException;
    7. import java.io.InputStream;
    8. public class WebUtil {
    9. public static User checkLogin(HttpServletRequest req){
    10. User user = null;
    11. HttpSession session = req.getSession(false);
    12. user = (User) session.getAttribute("user");
    13. return user;
    14. }
    15. //使用单例
    16. private static ObjectMapper mapper = new ObjectMapper();
    17. //反序列化:json字符串转换Java对象
    18. //使用泛型,传一个什么类型,就返回该类型的对象
    19. //泛型方法:方法限定符 <类型型参列表> 返回值类型 方法名
    20. public static T read(InputStream is,Class clazz){
    21. try {
    22. return mapper.readValue(is,clazz);
    23. } catch (IOException e) {
    24. throw new RuntimeException("json反序列化出错",e);
    25. }
    26. }
    27. //序列化:将java对象转化为json字符串
    28. public static String write(Object o){
    29. try {
    30. return mapper.writeValueAsString(o);
    31. } catch (JsonProcessingException e) {
    32. throw new RuntimeException("json序列化出错",e);
    33. }
    34. }
    35. }

    5.3 实体类model

    每张用户表对应有一个实体类,所以创建User和Article类,创建类的时候提供Getter和Setter方法并且重写toString方法

    用户类User

    1. public class User {
    2. private Integer id;
    3. private String username;
    4. private String password;
    5. private String nickname;
    6. @Override
    7. public String toString() {
    8. return "User{" +
    9. "id=" + id +
    10. ", username='" + username + '\'' +
    11. ", password='" + password + '\'' +
    12. ", nickname='" + nickname + '\'' +
    13. '}';
    14. }
    15. public Integer getId() {
    16. return id;
    17. }
    18. public void setId(Integer id) {
    19. this.id = id;
    20. }
    21. public String getUsername() {
    22. return username;
    23. }
    24. public void setUsername(String username) {
    25. this.username = username;
    26. }
    27. public String getPassword() {
    28. return password;
    29. }
    30. public void setPassword(String password) {
    31. this.password = password;
    32. }
    33. public String getNickname() {
    34. return nickname;
    35. }
    36. public void setNickname(String nickname) {
    37. this.nickname = nickname;
    38. }
    39. }

    文章类Article

    1. import java.util.Date;
    2. public class Article {
    3. private Integer id;
    4. private String title;
    5. private Date date; //时间
    6. private String content;
    7. private Integer userId;
    8. private String dateString;//日期字符串
    9. @Override
    10. public String toString() {
    11. return "Article{" +
    12. "id=" + id +
    13. ", title='" + title + '\'' +
    14. ", date=" + date +
    15. ", content='" + content + '\'' +
    16. ", userId=" + userId +
    17. ", dateString='" + dateString + '\'' +
    18. '}';
    19. }
    20. public Integer getId() {
    21. return id;
    22. }
    23. public void setId(Integer id) {
    24. this.id = id;
    25. }
    26. public String getTitle() {
    27. return title;
    28. }
    29. public void setTitle(String title) {
    30. this.title = title;
    31. }
    32. public Date getDate() {
    33. return date;
    34. }
    35. public void setDate(Date date) {
    36. this.date = date;
    37. }
    38. public String getContent() {
    39. return content;
    40. }
    41. public void setContent(String content) {
    42. this.content = content;
    43. }
    44. public Integer getUserId() {
    45. return userId;
    46. }
    47. public void setUserId(Integer userId) {
    48. this.userId = userId;
    49. }
    50. public String getDateString() {
    51. return dateString;
    52. }
    53. public void setDateString(String dateString) {
    54. this.dateString = dateString;
    55. }
    56. }

    Java对象JsonResult类 

    后端返回给前端的响应时返回的是json字符串,所以需要一个JsonResult类,该类的字段保存操作是否成功和要返回给前端的数据,后端在返回给前端json字符串的时候只需要将该类序列化为json字符串返回给前端,该类也得提供Getter与Setter方法并且重写toString方法

    1. public class JsonResult {
    2. private boolean ok;//标识执行一个操作是否成功
    3. private Object data;//操作成功,且是一个查询操作,需要返回一些数据给前端
    4. @Override
    5. public String toString() {
    6. return "JsonResult{" +
    7. "ok=" + ok +
    8. ", data=" + data +
    9. '}';
    10. }
    11. public boolean isOk() {
    12. return ok;
    13. }
    14. public void setOk(boolean ok) {
    15. this.ok = ok;
    16. }
    17. public Object getData() {
    18. return data;
    19. }
    20. public void setData(Object data) {
    21. this.data = data;
    22. }
    23. }

    5.4 前后端业务处理 

    前后端业务逻辑的实现顺序:

    1. 先在前端构造ajax请求 
    2. 再做后端业务逻辑
    3. 最后再前端才设置回调函数执行回调

    说明:后面实现的顺序是先前端再后端,但是观看参考时,建议按照上面的逻辑顺序,因为实际开发时就是按照这个顺序来开发的

    5.4.1 登陆页面功能设计 

    所有的请求都是使用ajax发送http请求,所以将封装的ajax函数写在一个js文件中,后续发送请求时只需将封装的ajax函数引入即可

    封装的ajax函数

    1. //封装ajax函数,args为一个js对象
    2. //args对象属性如下:
    3. //method:请求方法,url:请求资源路径,contenType:请求正文格式
    4. //body:请求正文,callback:回调函数,客户端接收到响应数据后调用
    5. function ajax(args) {
    6. let xhr = new XMLHttpRequest();
    7. //设置回调函数
    8. xhr.onreadystatechange = function () {
    9. //4:客户端接收到服务端响应
    10. if (xhr.readyState == 4) {
    11. //回调函数可能会使用响应的内容,作为传入参数
    12. args.callback(xhr.status, xhr.responseText);
    13. }
    14. }
    15. xhr.open(args.method, args.url);
    16. //如果args中contentType有内容,就设置Content-Type请求头
    17. if (args.contentType) {//js中if可以判断是否有值
    18. xhr.setRequestHeader("Content-Type", args.contentType);
    19. }
    20. //如果args中body有内容,设置body请求正文
    21. if (args.body) {
    22. xhr.send(args.body);
    23. } else {
    24. xhr.send();
    25. }
    26. }

    前端设计 

    1. 给登陆提交按钮绑定点击事件,获取到输入的用户名和密码后,发送ajax请求
    2. 请求方法为post,请求url为login,后端的Servlet路径也要与此对应,设置contentType为application/json,请求body为json字符串
    3. json对象保存输入的用户名和密码,将json对象转化为json字符串设置到body中
    4. 设置回调函数,回调函数有两个参数,一个为响应状态码,一个为后端返回的响应为json字符串,后端返回的json字符串中保存操作是否成功字段
    5. 如果响应状态码为200,并且ok为true,则登陆成功,跳转到博客列表页面,如果ok为false则用户名或密码错误,如果响应状态码不为200,则提示响应状态码及响应body,以便程序员作出更改
    1. <script src="js/util.js">script>
    2. <script>
    3. let submit = document.querySelector("#submit");
    4. //绑定提交按钮点击事件
    5. submit.onclick = function(){
    6. let username = document.querySelector("#username").value;
    7. let password = document.querySelector("#password").value;
    8. //发送ajax请求,需要设置method,url,contentType,body
    9. ajax({
    10. method: "post",
    11. url: "login",
    12. contentType: "application/json",
    13. body: JSON.stringify({
    14. //冒号前是前后端约定的键,冒号后是变量值
    15. username: username,
    16. password: password
    17. }),
    18. callback: function(status,responseText){
    19. if(status == 200){
    20. let json = JSON.parse(responseText);
    21. if(json.ok){
    22. alert("登陆成功");
    23. window.location.href = "blog_list.html";
    24. }else {
    25. alert("账号或密码错误");
    26. }
    27. }else {
    28. alert("响应状态码:"+status+"/nbody:"+responseText);
    29. }
    30. }
    31. });
    32. }
    33. script>

    后端Servlet设计

    1. 前端发送的body为json字符串
    2. 所以先使用InputStream输入流获取请求数据,将请求数据转化为user对象
    3. 使用该对象在数据库做校验,如果校验成功,设置session,设置要返回给前端的JsonResult对象json
    4. 设置完后,将json对象序列化json字符串后返回给前端
    5. 前端的回调函数就是依据后端返回的json字符串做相应的逻辑处理
    1. @WebServlet("/login")//登陆
    2. public class LoginServlet extends HttpServlet {
    3. //登陆功能,json提交{username:abc,password:123}
    4. @Override
    5. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    6. //解析请求:通过输入流获取请求数据
    7. req.setCharacterEncoding("utf-8"); //设置请求对象的编码格式
    8. InputStream is = req.getInputStream();
    9. //将输入流中的json字符串转化为java对象
    10. //使用ObjectMapper将java对象和json字符串相互转换,Servlet都要用,封装到WebUtil中
    11. User get = WebUtil.read(is,User.class);
    12. //在数据库校验账号密码:通过账号密码在数据库查用户,若能查到则账号密码正确
    13. User user = UserDao.isLogin(get.getUsername(),get.getPassword());
    14. //不管登陆是否成功,返回的http响应正文(body)都是json字符串
    15. //需要设计一个类,这个类的成员变量属性,用于前端ajax解析响应
    16. //先创建一个响应正文需要的Java对象,然后在转换为json字符串,再设置到响应正文
    17. JsonResult json = new JsonResult();
    18. if(user != null){
    19. //登陆成功,设置session
    20. HttpSession session = req.getSession(true);
    21. session.setAttribute("user",user);
    22. //设置json对象中,操作是否成功为true
    23. json.setOk(true);
    24. }else {
    25. //登陆失败,设置操作是否成功字段为false
    26. json.setOk(false);
    27. }
    28. //设置响应正文的格式
    29. resp.setContentType("application/json; charset=utf-8");
    30. resp.getWriter().write(WebUtil.write(json));
    31. }
    32. }

    5.4.2 博客列表页面功能设计

    前端设计

    客户端展示页面时,就需要展示文章列表数据,加载完页面就发生ajax请求,来获取文章列表内容,待收到返回的响应执行回调时,解析响应的文章列表数据

    1. 发送的ajax请求,method为get,url为blog_list,对应的后端Servlet路径也要与之对应
    2. 因为是get请求,所以没有body
    3. 设置回调函数,与前面登陆的回调函数逻辑相似,将后端返回的json字符串转化为json对象时,如果ok为true,则解析返回的数据
    4. 将返回的nickname和文章数设置到前端,将返回的文章集合以循环的方式设置到前端 
    1. <script src="js/util.js">script>
    2. <script>
    3. //客户端展示页面时,就需要展示文章列表数据
    4. //加载完页面,就发送ajax请求获取文章列表的数据
    5. //返回响应执行回调时,解析响应的文章列表数据
    6. ajax({
    7. method: "get",
    8. url: "blog_list",
    9. callback: function(status,responseText){
    10. if(status == 200){
    11. let json = JSON.parse(responseText);
    12. if(json.ok){
    13. let data = json.data;
    14. let nickname = data.nickname;
    15. let h3 = document.querySelector(".card>h3");
    16. h3.innerHTML = nickname;
    17. let articles = data.articles;
    18. let div = document.querySelector(".container-right");
    19. //str不赋值就是undefined,再去拼接字符串就会出错
    20. let str = "";
    21. for(let a of articles){
    22. //``里面可以包括单引号和双引号
    23. str += `
      `;
    24. str += `
      `;
    25. str += a.title;
    26. str += `
      `;
  • str += `
    `;
  • str += a.dateString;
  • str += `
    `;
  • str += `
    `;
  • str += `

    `;

  • str += a.content;
  • str += `

    `
    ;
  • str += `
    `;
  • str += `
    `;
  • str += `id;
  • str += `
    `;
  • str += `
    `;
  • }
  • 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设计

    1. 先校验用户是否登陆,未登录不允许访问,直接跳转到用户登陆页面,登陆后才可执行后边逻辑
    2. 登陆成功后用用户的id查询该用户的所有文章并且查询该用户的所有文章数目
    3. 此时已经登陆成功,设置JsonResult对象json的ok为true
    4. 创建一个Map结构的data,保存要返回给前端的数据文章列表和用户昵称和文章数目
    5. 将data设置到json对象中,将json对象序列化为json字符串返回给前端
    1. @WebServlet("/blog_list")//博客列表
    2. public class BlogListServlet extends HttpServlet {
    3. @Override
    4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. //未登录,访问跳转到登陆页面
    6. User user = WebUtil.checkLogin(req);
    7. if(user == null){
    8. resp.sendRedirect("login.html");
    9. return; //未登录,直接跳转,不会执行后边逻辑
    10. }
    11. //通过登陆用户id查找所有文章
    12. List
      articles = ArticleDao.selectById(user.getId());
    13. //通过登陆用户id查找文章数目
    14. int count = ArticleDao.getCount(user.getId());
    15. //先构造响应正文需要的java对象,再转化为json字符串,再设置到响应正文
    16. JsonResult json = new JsonResult();
    17. json.setOk(true);
    18. //前端需要的数据有nickname,articles,可以用map保存,然后设置到json.data中
    19. Map data = new HashMap<>();
    20. data.put("nickname",user.getNickname());
    21. data.put("articles",articles);
    22. data.put("count",count);
    23. json.setData(data);
    24. resp.setContentType("application/json; charset=utf-8");
    25. resp.getWriter().write(WebUtil.write(json));
    26. }
    27. }

    5.4.3 博客详情页面功能设计 

    前端设计 

    博客详情是从博客列表的显示全文按钮跳转过来的,所以跳转的连接携带id,id标识文章id,表示显示的是哪篇文章的全部内容

    1. 先使用window.location.search.substring获取到文章id
    2. 再发送ajax请求,请求方法为get,请求url为blog_content?id=id,设置回调函数
    3. 待后端返回响应后执行回调函数,将响应正文转化为json对象,解析json对象
    4. 设置用户昵称,文章数目,文章标题,发表日期,文章内容 
    1. <script src="js/util.js">script>
    2. <script>
    3. //window.location.search获取的是queryString?后的部分,blog_content?id=1
    4. //也就是获取的是?id=1
    5. let id = window.location.search.substring(4);
    6. //页面一加载就需要展示博客详情页面,所以就发送ajax请求来获取内容
    7. ajax({
    8. method: "get",
    9. url: "blog_content?id="+id,
    10. callback: function(status,responseText){
    11. if(status == 200){
    12. let json = JSON.parse(responseText);
    13. if(json.ok){
    14. let data = json.data;
    15. let nickname = data.nickname;
    16. let h3 = document.querySelector(".card>h3");
    17. h3.innerHTML = nickname;
    18. let num = data.count;
    19. let count = document.querySelector("#count");
    20. count.innerHTML = num;
    21. let article = data.article;
    22. let div = document.querySelector(".detail");
    23. let str = "";
    24. str += `
      `;
    25. str += article.title;
    26. str += `
      `;
    27. str += `
      `;
    28. str += article.dateString;
    29. str += `
      `;
    30. str += `
      `;
    31. //str += article.content;
    32. str += `
      `;
    33. div.innerHTML = str;
    34. //不能直接展示markdown源码,数据库保存的是markdown源码
    35. editormd.markdownToHTML("article-content",{markdown: article.content});
    36. }else {
    37. alert("ok == false");
    38. }
    39. }else {
    40. alert("响应状态码:"+status+"/nbody:"+responseText);
    41. }
    42. }
    43. });
    44. script>

    后端Servlet设计

    1. 用户未登录不允许访问,直接跳转到用户登陆页面
    2. 请求数据携带在queryString中,所以使用req.getParameter解析请求获取到文章id
    3. 根据文章id查询整个文章将查询的数据设置到一个文章对象中
    4. 将JsonResult对象json的ok设置为true
    5. 使用一个Map结构data保存获取的文章数目,文章,用户昵称
    6. 将data设置到json对象中,将json对象序列化为json字符串后返回给前端 
    1. @WebServlet("/blog_content")//博客详情
    2. public class BlogContentServlet extends HttpServlet {
    3. @Override
    4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. //未登录,访问跳转到登陆页面
    6. User user = WebUtil.checkLogin(req);
    7. if(user == null){
    8. resp.sendRedirect("login.html");
    9. return; //未登录,直接跳转,不会执行后边逻辑
    10. }
    11. //路径为:blog_content?id=文章id
    12. //解析请求
    13. String sid = req.getParameter("id"); //获取到文章id
    14. //通过文章id查询整篇文章
    15. Article a = ArticleDao.queryById(Integer.parseInt(sid));
    16. int count = ArticleDao.getCount(user.getId());
    17. JsonResult json = new JsonResult();
    18. json.setOk(true);
    19. Map data = new HashMap<>();
    20. data.put("nickname",user.getNickname());
    21. data.put("article",a);
    22. data.put("count",count);
    23. json.setData(data);
    24. resp.setContentType("application/json; charset=utf-8");
    25. resp.getWriter().write(WebUtil.write(json));
    26. }
    27. }

    5.4.4 博客编辑页面功能设计

    前端设计

    1. 给发布文章绑定点击事件,点击发布,发送ajax请求用于给文章表中添加数据
    2. 获取到输入的文章标题和文章内容,将其设置为json对象
    3. 发送ajax请求的方法为post,url为blog_add,后端Servlet路径要与之对应,设置contentType为application/json,将设置的json对象转化为json字符串设置到body中
    4. 待收到后端返回的响应后,执行回调,提示发布文章成功并且跳转到博客列表页面 
    1. <script src="js/util.js">script>
    2. <script src="js/jquery.min.js">script>
    3. <script src="editor.md/lib/marked.min.js">script>
    4. <script src="editor.md/lib/prettify.min.js">script>
    5. <script src="editor.md/editormd.min.js">script>
    6. <script>
    7. $(function(){
    8. var editor = editormd("edit-content",{
    9. width: "100%",
    10. height: "calc(100% - 50px)",
    11. markdown: "# 在这里写下第一篇博客",
    12. path: "editor.md/lib/",
    13. saveHTMLToTextarea: true
    14. });
    15. })
    16. //发布文章点击事件
    17. function addContent(){
    18. let title = document.querySelector("#title").value;
    19. let content = document.querySelector("#content").value;
    20. ajax({
    21. method: "post",
    22. url: "blog_add",
    23. contentType: "application/json",
    24. body: JSON.stringify({
    25. title: title,
    26. content: content
    27. }),
    28. callback: function(status,responseText){
    29. if(status == 200){
    30. let json = JSON.parse(responseText);
    31. if(json.ok){
    32. alert("发布文章成功");
    33. window.location.href = "blog_list.html";
    34. }else {
    35. alert("ok == false");
    36. }
    37. }else {
    38. alert("响应状态码:"+status+"/nbody:"+responseText);
    39. }
    40. }
    41. });
    42. }
    43. script>

    后端Servlet设计

    1. 用户未登录不允许访问,直接跳转到用户登录页面
    2. 使用InputStream解析请求,通过输入流获取数据
    3. 将输入流中的json字符串转化为文章对象
    4. 设置用户id,发布日期到该文章对象中
    5. 将JsonResult对象json的ok设置为true,将json对象序列化为json字符串后返回给前端
    1. @WebServlet("/blog_add")//添加文章
    2. public class BlogAddServlet extends HttpServlet {
    3. @Override
    4. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. User user = WebUtil.checkLogin(req);
    6. if(user == null){
    7. //未登录不允许访问
    8. resp.sendRedirect("login.html");
    9. return;
    10. }
    11. //解析请求
    12. req.setCharacterEncoding("utf-8");
    13. InputStream is = req.getInputStream();
    14. Article beInsert = WebUtil.read(is,Article.class);
    15. //数据库插入一条数据,相当于插入一个对象
    16. beInsert.setUserId(user.getId());
    17. beInsert.setDate(new java.util.Date());
    18. int n = ArticleDao.insertOne(beInsert);
    19. JsonResult json = new JsonResult();
    20. json.setOk(true);
    21. resp.setContentType("application/json; charset=utf-8");
    22. resp.getWriter().write(WebUtil.write(json));
    23. }
    24. }

    5.4.5 用户注销功能设计

    1. 获取到session
    2. 如果session不为空,将session中保存的user删除
    3. 删除后跳转到用户登陆页面 
    1. @WebServlet("/logout")
    2. public class LogoutServlet extends HttpServlet {
    3. @Override
    4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. //注销就是通过session对象删除保存的用户信息
    6. HttpSession session = req.getSession(false);
    7. if(session != null){
    8. session.removeAttribute("user");
    9. }
    10. resp.sendRedirect("login.html");
    11. }
    12. }

    6. 数据库逻辑处理 

    前端后端做业务处理的数据库逻辑操作如下: 

    6.1 用户表的逻辑处理

    通过登陆输入的用户名和密码查询到user并将user返回,以此来做用户密码校验功能

    1. public class UserDao {
    2. public static User isLogin(String username, String password){
    3. Connection c = null;
    4. PreparedStatement ps = null;
    5. ResultSet rs = null;
    6. try {
    7. c = DBUtil.getConnection();
    8. String sql = "select * from user where username=? and password=?";
    9. ps = c.prepareStatement(sql);
    10. ps.setString(1,username);
    11. ps.setString(2,password);
    12. rs = ps.executeQuery();
    13. User user = null;
    14. while(rs.next()){
    15. user = new User();
    16. int id = rs.getInt("id");
    17. String nickname = rs.getString("nickname");
    18. user.setId(id);
    19. user.setNickname(nickname);
    20. user.setUsername(username);
    21. user.setPassword(password);
    22. }
    23. return user;
    24. } catch (SQLException e) {
    25. throw new RuntimeException("校验账号密码出错",e);
    26. } finally {
    27. DBUtil.close(c,ps,rs);
    28. }
    29. }
    30. @Test
    31. public void testLogin(){
    32. System.out.println(isLogin("abc","123"));
    33. }
    34. }

    6.2 文章表的逻辑处理 

    通过用户id查询所有文章

    1. //通过用户id查询所有文章
    2. public static List
      selectById(Integer id){
    3. List
      articles = new ArrayList<>();
    4. Connection c = null;
    5. PreparedStatement ps = null;
    6. ResultSet rs = null;
    7. try{
    8. c = DBUtil.getConnection();
    9. String sql = "select * from article where user_id=?";
    10. ps = c.prepareStatement(sql);
    11. ps.setInt(1,id);
    12. rs = ps.executeQuery();
    13. while(rs.next()){
    14. Article a = new Article();
    15. a.setId(rs.getInt("id"));
    16. a.setTitle(rs.getString("title"));
    17. java.sql.Date date = rs.getDate("date");
    18. long time = date.getTime();
    19. a.setDate(new java.util.Date(time));
    20. DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    21. String dateString = df.format(a.getDate());
    22. a.setDateString(dateString);
    23. String content = rs.getString("content");
    24. a.setContent(content.length()>50 ? content.substring(0,50) : content);
    25. a.setUserId(id);
    26. articles.add(a);
    27. }
    28. return articles;
    29. } catch (SQLException e) {
    30. throw new RuntimeException("查询文章出错",e);
    31. } finally {
    32. DBUtil.close(c,ps,rs);
    33. }
    34. }

    根据文章id查询整篇文章

    1. //根据文章id查文章
    2. public static Article queryById(int id) {
    3. Article a = null;
    4. Connection c = null;
    5. PreparedStatement ps = null;
    6. ResultSet rs = null;
    7. try{
    8. c = DBUtil.getConnection();
    9. String sql = "select * from article where id=?";
    10. ps = c.prepareStatement(sql);
    11. ps.setInt(1,id);
    12. rs = ps.executeQuery();
    13. while(rs.next()){
    14. a = new Article();
    15. a.setId(id);
    16. a.setTitle(rs.getString("title"));
    17. java.sql.Date date = rs.getDate("date");
    18. DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    19. String dateString = df.format(new java.util.Date(date.getTime()));
    20. a.setDateString(dateString);
    21. a.setContent(rs.getString("content"));
    22. a.setUserId(rs.getInt("user_id"));
    23. }
    24. return a;
    25. } catch (SQLException throwables) {
    26. throw new RuntimeException("查询文章详情jdbc出错",throwables);
    27. } finally{
    28. DBUtil.close(c,ps,rs);
    29. }
    30. }

    插入一篇文章 

    1. //插入文章
    2. public static int insertOne(Article a) {
    3. Connection c = null;
    4. PreparedStatement ps = null;
    5. try{
    6. c = DBUtil.getConnection();
    7. String sql = "insert into article(title,`date`,content,user_id) values(?,?,?,?)";
    8. ps = c.prepareStatement(sql);
    9. ps.setString(1,a.getTitle());
    10. //ps.setDate(2,new java.sql.Date(a.getDate().getTime()))
    11. ps.setDate(2,new java.sql.Date(System.currentTimeMillis()));
    12. ps.setString(3,a.getContent());
    13. ps.setInt(4,a.getUserId());
    14. return ps.executeUpdate();
    15. } catch (SQLException throwables) {
    16. throw new RuntimeException("发布文章jdbc出错",throwables);
    17. } finally {
    18. DBUtil.close(c,ps);
    19. }
    20. }

    获取文章数目

    1. public static int getCount(Integer id) {
    2. Connection c = null;
    3. PreparedStatement ps = null;
    4. ResultSet rs = null;
    5. try{
    6. c = DBUtil.getConnection();
    7. String sql = "select 0 from article where user_id=?";
    8. ps = c.prepareStatement(sql);
    9. ps.setInt(1,id);
    10. rs = ps.executeQuery();
    11. int count = 0;
    12. while(rs.next()){
    13. count++;
    14. }
    15. return count;
    16. } catch (SQLException throwables) {
    17. throw new RuntimeException("查询文章数目出错",throwables);
    18. } finally{
    19. DBUtil.close(c,ps,rs);
    20. }
    21. }

    7. 博客系统设计源码

    在做前后端逻辑处理的时候,前端代码有些稍微的改动,本文没有提及到,请点击查看源码,查看改动的细节以及所有后端的设计实现:个人博客系统设计源码

  • 相关阅读:
    继承和组合
    【EXCEL】详解使用python读写EXCEL文件(xlrd,xlwt)
    【Unity3D】视图中心 ( 视图中心概念 | 围绕游戏物体旋转 | 添加游戏物体到游戏场景的位置 )
    STM32 CAN使用
    APEX:开启Android系统新篇章的应用扁平化技术
    Python 潮流周刊第 44 期(摘要)+ 赠书 5 本《明解Python算法与数据结构》
    Spring Boot 到底是单线程还是多线程
    mac的node版本安装及升降级
    iHRM 人力资源管理系统_第9章_文件上传与PDF报表入门_第一节_文件上传
    含文档+PPT+源码等]精品基于PHP实现的商城电商网站[包运行成功]
  • 原文地址:https://blog.csdn.net/qq_58710208/article/details/126957212