一、搭建项目环境
- 创建好目录
- 引入依赖
( Servlet、MySQL、Thymeleaf ) - 往 web.xml 文件中放入一些代码
- 部署程序
( 通过 Smart Tomcat 进行部署 ) - 验证是否就绪
( 通过一个 HelloServlet 类验证 )
二、设计数据库
- 通过自己写的 sql 语句,往 MySQL 数据库中,插入【blog 表】、【user 表】
【blog 表】 预期用来存储博客的信息 ( 标题、内容、发布时间 )
【user 表】预期用来存储用户的信息 ( 用户账号、用户密码 )
create database if not exists practice_blog; use practice_blog; -- 创建博客表 drop if exists blog; create table blog ( -- 博客 ID (自增主键) blogID int primary key auto_increment, -- 博客标题 (字符串类型) title varchar(50), -- 博客内容 (字符串类型,表示中等长度文本) content mediumtext, -- 博客发布的时间 (日期类型) postTime datetime, -- 作者的账号ID userID int ); -- 创建用户表 drop if exists user; create table user ( -- 用户的账号ID (自增主键) userID int primary key auto_increment, -- 用户的账号 (保证用户名唯一) username varchar(50) unique, -- 用户的密码 password varchar(20) );
三、根据数据库设计实体类
1. Blog 类
public class Blog { private int blogID; private String title; private String content; private Timestamp postTime; private int userID; }
2. User 类
public class User { private int userID; private String username; private String password; }
四、封装数据库
JDBC 编程步骤
- 创建数据源
- 和数据库建立连接
- 构造 sql 语句并操作数据库
- 执行 sql
- 遍历结果集(select 查询的时候需要有这一步)
- 释放资源
1. 创建一个 DBUtil 类 ( Database Utility )
public class DBUtil { private static final String URL = "jdbc:mysql://127.0.0.1:3306/practice_blog?characterEncoding=utf8&&useSSL=false"; private static final String USERNAME = "root"; private static final String PASSWORD = "123456789"; // 1. 创建数据源 private static volatile 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; } // 2. 建立连接 public static Connection getConnection() throws SQLException { return getDataSource().getConnection(); // 实际上返回的是 dataSource.getConnection() // 让外面的类能够 Connection connection = dataSource.getConnection(); // 即与数据库建立连接 } // 代码最后,应该记得释放资源 public static void close(ResultSet resultSet, PreparedStatement statement, Connection connection) { 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(); } } } }
DBUtil 这个类,用来封装一些数据库的方法,供外面的类使用。
好处一:外面的类需要创建一些同样的实例, 这些实例是固定的。然而,有了DBUtil这个类,外面的类就不需要每次创建额外的实例,直接从 DBUtil 类 拿即可。
( DBUtil 中的单例模式正是做到了这一点)
好处二:同样地,外面的类需要用到一些同样的方法,有了 DBUtil 这个类,对于代码与数据库之间的一些通用的操作方法,直接从 DBUtil 类 导入即可。
我们可以将 DBUtil 这个类想象成一个充电宝,而将使用这个 DBUtil 公共类的其他类,称为手机、平板、mp3…毫无疑问,充电宝就是为电子设备提供服务的,而这些电子设备其实只有一个目的:通过充电宝这个公共资源为自己充电。
2. 封装 BlogDB ( Blog Database )
(1) insert 方法
插入一篇博客,( 博客从浏览器编写,然后上传到服务器,服务器再上传到数据库 )
(2) searchAll 方法
查找所有博客,为了后续展示在博客列表页
(3) searchOne 方法
查找单篇博客,为了后续展示在博客内容页
(4) deleteOne 方法
删除博客,为了后续在浏览器页面上点击生效
(5) findCount 方法
查找当前用户的文章总数
3. 封装 UserDB( User Database )
(1) insert 方法
插入一名用户,( 从前端输入账号和密码上传到服务器,服务器再上传到数据库 )
(2) searchByUsername 方法
通过 username 来查找用户
(3) searchByUserID 方法
通过 userID 来查找用户
五、定好前后端交互的思路
1. 实现每个页面的思想
- 博客列表页
- 博客内容页
- 博客登录页
- 博客编辑页
博客列表页和博客内容页是通过 ajax 发送的 HTTP请求,之后在服务器端计算响应的。前端主要处理页面逻辑,后端主要处理返回数据。
而登录页和编辑页,我们通过 form 表单的形式来构造 HTTP请求。
必须明确:
列表页和内容页是通过 浏览器输入 URL 路径这种形式来构造 HTTP 请求的。这种方式,绝大多数情况下,都是一个 GET 请求,所以,我们需要在 Servlet 代码中,构造 GET 响应。
登录页和编辑页是通过 form 表单的形式构造 HTTP 请求的,一般和 input 标签相关的提交按钮,都是 POST 方法。
2. ajax 构造 HTTP 请求的格式
由于 ajax 的原生用法较为麻烦,工作中也不太可能用到,所以,我们就通过 JS 引入第三方库 jQuery. jQuery 其实是一个功能非常全面的库,它对 DOM API 进行了非常好的封装。我们只需要在 JS 代码中,引入 jQuery 所在的网络地址,就能直接使用,当然,如果下载到本地,也是可以使用的。(这种方式较为稳定,更为推荐)
在本篇博客中,我是下载到了本地使用,这样对于展示给用户看来说,更为稳定。
<body> <!-- 引入 jQuery --> <script src="js/jquery.min.js"></script></script> <script> //ajax 方法传参传的是一个大括号对象 $.ajax({ // url 中填写需要访问的服务器地址 url: '', //这就表示一个 GET 方法 method: 'GET', //data 就是响应的 body,status 就是响应的状态码 success: function(data, status) { } error: function(data, status) { } }); </script> </body>
(1) 理解 success 回调函数
关于 success 这个回调函数:顾名思义,它表示从客户端发送 HTTP 请求成功后,浏览器调用此函数。一般来说,success 其实就意味着 HTTP 响应的状态码是 200.
回调函数并不是自己调用,而是让浏览器在合适的时机自己调用的,这一点需要格外注意。
所以,一般来说,success 这个回调函数中,需要写入的业务逻辑,一般就是为了展示给用户观看的内容。即前端开发人员决定在这里面实现什么给用户看。
问1:那么业务逻辑的数据从哪来?
答:业务逻辑的数据就是从传入的参数 data 中获取到的。
问2:那么 data 从哪来?
答:data 就是从 HTTP 响应的正文 body 来获取的。
问3:正文 body 又从哪来?
答:HTTP 响应的正文 body 其实就是服务器端的代码构造的,常用的就是 json 格式数据,因为 json 格式的数据是可以将很多复杂的文本组合在一起。所以,后端的开发人员,一般通过将 Java 对象转换成 json 格式的数据,放到 响应的 body 中。在本篇博客中,就是以 json 格式的数据放置的,后面会进行细说。
(2) error 回调函数
success 一般对应着 状态码 200,而 error 一般对应着 除 200 之外的状态码。因为顾名思义,在回调函数的业务逻辑中,就是用来处理【客户端发送 HTTP 请求失败的情况】,这些情况可能是路径问题,可能是密码错误问题,也可能是用户权限问题等等…
3. 服务器端往 HTTP 响应中写入 json 格式的数据
问1:为什么在这里写入 json 格式的数据
答:因为 json 格式的数据可以将很多复杂的文本组合在一起,或者说,将一些杂乱无章的字符串组合在一起。此外,实际上我们不可能直接将 Java 对象直接就放入到响应的 body 中。
综上所述,我们可以将 Java 对象转换成一个 json 格式,Java 对象或变量,或数组,或字符串等等…都可以转化成一个 json 格式的数据。也就是说,json 格式的数据能够很好的与 Java 对象进行形式切换,但数据的内容相同,只是格式不同罢了。
这就好像:美国人用英语说 “hello”,中国人用中文说 “你好”,其实是一个意思,但是中国人需要出国留学,就要入乡随俗,此时,中国人也要说英语,才能与美国本土人进行正常沟通。
然而,json 格式本身,是比较复杂的,因为 json 大括号中,可以嵌套很多层的数据,如果直接通过代码解析,这就会增大任务量。所以,更好的办法,就是直接使用第三方库。在 Java 中,能够解析 json 格式的第三方库有很多,这些库的用法和性能方面其实都差不多,在这里,我们使用 Jackson 这样的库,因为 Jackson 是 Spring全家桶中,指定使用的 json 库,后期学习到 Spring 框架的时候,也能够很好地联系起来。
格式:
public class BlogServlet extends HttpServlet { // jackson 提供的核心类 private ObjectMapper objectMapper = new ObjectMapper(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置 【写入 HTTP 响应的正文 body 格式】为 json 类型 resp.setContentType("application/json; charset=UTF-8"); // 将 Java 对象转换成一个 json 格式的类型 String jsonData = objectMapper.writeValueAsString(blog); // 写入 HTTP 响应的正文 body 中 resp.getWriter().write(jsonData); } }