前面学习了那么多的理论知识,一直比较枯燥,今天就做个小项目,来检验一下前面的学习成果吧!有需要源代码的小伙伴可以来看看:个人博客系统;这个小项目主要是模仿CSDN做的,但是功能还是比较少的,只是写出了一些主要的功能,下面就一起来看看吧!???
目录
? 一.准备工作?1.创建maven项目?2.引入各种依赖?3.创建必要的目录?4.编写代码?5.打包部署(基于smart Tomcat)?6.验证 ? 二.编写前端代码? 三.数据库相关代码? 四.具体的功能?1.查询博客列表页功能?2.查询博客详情页功能?3.登录功能?4.检验当前页面登录状态功能?5.显示用户信息到页面功能?6.注销功能?7.发布博客功能?8.删除博客功能 ? 五.总结与思考
? 一.准备工作
这里的准备工作主要就是测试一下环境是否正常,编写一些简单的代码来验证页面是否可以顺利访问!
?1.创建maven项目
?2.引入各种依赖
这里主要引入需要用到的各种依赖包:
<dependencies> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.6.1</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies>
全部放在dependencies标签里面
?3.创建必要的目录
在webapp目录下就可以放置所编写好的前端页面了,切记不是放在WEB-INF目录下!!!
?4.编写代码
这里写简单的代码进行测试环境
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 java.io.IOException;@WebServlet("/hello")public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello world"); }}
?5.打包部署(基于smart Tomcat)
使用smart Tomcat一键打包部署
?6.验证
这样环境就没有问题了,就可以进行下面的一系列代码的编写了!
? 二.编写前端代码
前端页面就直接演示成果了:
登录页面:
博客列表页面:
博客详情页面:
博客编辑页面:
? 三.数据库相关代码
数据库相关的代码就需要根据需求来确定其如何编写:而要完成博客项目最主要的两个点就是用户和博文因此就需要创建两个表:用户表和博客表,然后再完成各种增删改查之类的操作
就使用用户表举个例子:
首先就需要在数据库中创建相关的表,才可以进行加下来的操作:
drop table if exists user;create table user( userId int primary key auto_increment, username varchar(128) unique, -- 后续会使用这个用户名进行登录,用户名不能重复 password varchar(128));
然后再进行数据库连接(JDBC)的操作:
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 { private static final String URL = "jdbc:mysql://127.0.0.1:3306/my_blog?characterEncoding=utf8&useSSL=false"; private static final String USERNAME = "root"; private static final String PASSWORD = "123"; //设计懒汉单例模式 需要时再进行连接,需要注意线程安全问题 private volatile static DataSource dataSource = null; private static DataSource getDataSource(){ if(dataSource == null){ synchronized (DBUtil.class){ if(dataSource == null){ dataSource = new MysqlDataSource(); ((MysqlDataSource)dataSource).setURL(URL); ((MysqlDataSource)dataSource).setUser(USERNAME); ((MysqlDataSource)dataSource).setPassword(PASSWORD); } } } return dataSource; } //进行连接 public static Connection getConnection() throws SQLException { return getDataSource().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(); } } }}
然后可以通过用户id来查找信息:
public User selectById(int userId){ Connection connection = null; PreparedStatement statement = null; ResultSet resultSet = null; try { connection = DBUtil.getConnection(); //sql语句 String sql = "select * from user where userId = ?"; statement = connection.prepareStatement(sql); statement.setInt(1,userId); //执行sql语句 resultSet = statement.executeQuery(); //遍历结果 由于这里是主键,因此也是使用if而不是while 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; }
当然这里要查找需要数据内用东西,才能进行查找,而其他的操作都是和这个类似,这里就不过多演示了!
? 四.具体的功能
这里的功能实现起来基本都是先完成约定前后端交互接口,然后再编写客户端的请求,以及服务器的相应处理,而前端和后端唯一的联系就是这些约定好的接口!在这里我用查询博客列表页进行代码演示!
?1.查询博客列表页功能
通过查询可以直接查询到数据库内的所有博客信息,然后就可以列举在博客详情页面了(按照发布时间的先后顺序):
前后端交互接口:
请求:GET /blog响应:[ { blogId: 1, title: '这是第一篇博客', content: '这是博客正文(缩写版)', userId: 1, postTime: '2022-06-04 21:21:00' }, { blogId: 2, title: '这是第二篇博客', content: '这是博客正文(缩写版)', userId: 2, postTime: '2022-06-04 21:21:00' }]
然后根据约定好的接口进行各自处理:
请求:
//页面加载的时候,使用ajax给服务器发送请求,获取到相应的响应 function getBlogList(){ $.ajax({ type: 'get', url: 'blog', success: function(body){ //此时的body就是一个js对象数组(这里的转换是原生就转换好的),每一个元素就是js对象,然后这里就需要把这些js对象构造成形如上面的类型 //1.先把right里面的内容进行清空操作,然后再进行插入操作 let rightDiv = document.querySelector(".right"); //将里面的内容进行清空 rightDiv.innerHTML = ''; //然后再遍历整个js数组,往right里面插入元素 for(let blog of body){ //先构造一个blogDiv,然后往里面插入对应的元素,然后再将这个blogDiv插入到right里面就可以l //这里都是createElement不是querySelector.... 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.innerHTML = blog.content; descDiv.className = 'desc'; blogDiv.appendChild(descDiv); //查看全文链接 let a = document.createElement('a'); a.innerHTML = "查看全文 >>"; //设置a.href点击这个连接之后可以进行跳转到博客详情页面 //这个跳转就需要告知服务器要访问的是哪个博客的详情页 a.href = "blog_detail.html?blogId=" + blog.blogId; blogDiv.appendChild(a); //最后需要把整个blogDiv插入到完整的rightDiv中去 rightDiv.appendChild(blogDiv); } }, error: function(){ //console.log("获取博客列表失败"); alert("获取博客列表失败!"); } }); } //调用这个方法 getBlogList();
服务器返回的响应:
@WebServlet("/blog")public class BlogServlet extends HttpServlet { private ObjectMapper objectMapper = new ObjectMapper(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //这里就需要把数据库中的数据查询出来,然后转换成JSON格式,输出就可以了 //通过封装数据库操作的类来进行查询 BlogDao blogDao = new BlogDao(); //防止乱码,这个和下面的顺序不能颠倒,先设置字符,再输出 resp.setContentType("application/json;charset=utf8"); //表示没有参数,就是获取博客列表内容 //把查询的结果放到一个数组中 List<Blog> blogs = blogDao.selectAll(); //然后通过objectMapper把这个转换成JSON格式,再进行输出 String respJson = objectMapper.writeValueAsString(blogs); //然后输出就可以了 resp.getWriter().write(respJson); } }
这样的前后端分离,也使得前端和后端的程序员互不影响,也是方便了很多!
?2.查询博客详情页功能
在博客列表页的时候,有一个查看全文的按钮,通过这个按键就可以发送请求,然后查询到该篇博客的具体内容了:
?3.登录功能
输入正确的用户名和密码即可进行登录:
?4.检验当前页面登录状态功能
如果尚未登录就会出现提示登录的弹框,然后会跳转到登录页面:
?5.显示用户信息到页面功能
?6.注销功能
点击注销即可即可退出登录,跳转到博客登录页面
?7.发布博客功能
当博客正文和标题都写完之后点击发布,即可完成发布,然后在博客列表页就可以看到此文章!
?8.删除博客功能
在博客详情页,当你是这篇博客的作者的时候,便会出现一个删除博客按键,点击即可进行删除,而不是此博客的作者的话,就不会有这个按钮:
? 五.总结与思考
从这个小项目中可以深切的体会到前后端分离的好处,每一次前端和后端的交互都只需要看前后端约定好的交互接口就完全可以实现自己的东西了,这也很大程度上提高了开发的效率,不至于让前端和后端的程序员"无事可做",而且也不需要程序员全干,只需要做自己的事情就可以了!!!
另外这个小项目所涉及到的功能也是不完善的,像注册,删除用户信息,修改博客之类的很多功能,并没有体现出来,但是这些实现起来和上面的实现是查不了多少的,而我在这里就不体现了,需要的朋友可以自行实现一下,和上面的是差不多的,另外上面也是写了很多重复的代码,这些对于我们聪明的程序员来说是非常不友好的,因此后面我会再基于框架将这个小项目重新完成,使用起来框架就会发现简单了很多!这个就后面再谈吧!!!