使用servlet,实现前后端交互,通过jdbc和mysql数据库进行数据传输,使得可以将用户信息和博客列表存储在数据库中,实现真正的服务器,客户端,数据库三者的交互
在sql数据库中建立数据库,建立用户表和博客列表
create database if not exists Lx_blog charset utf8mb4;
use Lx_blog;
drop table if exists blog;
create table blog (
blogId int primary key auto_increment,
title varchar(1024),
content mediumtext,
userId int,
postTime datetime
);
insert into blog values(null,"这是第一篇博客", "从今天开始,我要一天写一篇博客",1,now());
insert into blog values(null,"这是第二篇博客", "从今天开始,我要一天写两篇博客",1,now());
insert into blog values(null,"这是第三篇博客", "从今天开始,我要一天写三篇博客",1,now());
insert into blog values(null,"这是第一篇博客", "从今天开始,我胡汉三要一天写一篇博客",2,now());
insert into blog values(null,"这是第一篇博客", "从昨天开始,我胡汉三要一天写两篇博客",2,now());
insert into blog values(null,"这是第三篇博客", "# 一级标题\n ### 三级标题\n > 引用内容",2,now());
drop table if exists user;
create table user (
userId int primary key auto_increment,
username varchar(128) unique,
password varchar(128)
);
insert into user values(null, '123', 1234);
insert into user values(null, 'xiao', 8830);
实现jdbc的基础代码——获取DataSource的方法,获取connection的方法,close各种资源的方法
package model;
import com.mysql.cj.jdbc.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/Lx_blog?characterEncoding=utf-8";
private static final String USERNAME = "root";
private static final String PASSWORD = "";
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;
}
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,标题,内容,用户id,提交时间,及一系列get和set方法
package model;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
public class Blog {
private int blogId;
private String title;
private String content;
private int userId;
private Timestamp postTime;
public int getBlogId() {
return blogId;
}
public void setBlogId(int blogId) {
this.blogId = blogId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
// public Timestamp getPostTime() {
// return postTime;
// }
public String getPostTime(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
}
用户对象,其包括用户id,用户名和密码,及一系列get和set方法
package model;
public class User {
private int userId = 0;
private String username = "";
private String password = "";
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
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;
}
}
通过调用jdbc中的一系列查询和插入方法,实现新增博客,获取所有博客,通过博客id获取单一博客的方法
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class BlogDao {
public void insert(Blog blog){
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "insert into blog values(null, ?, ?, ?, now())";
statement = connection.prepareStatement(sql);
statement.setString(1, blog.getTitle());
statement.setString(2, blog.getContent());
statement.setInt(3, blog.getUserId());
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection,statement,null);
}
}
public List<Blog> selectAll(){
List<Blog> blogs = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try{
connection = DBUtil.getConnection();
String sql = "select * from blog order by postTime desc";
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while(resultSet.next()){
Blog blog = new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
String content = resultSet.getString("content");
if(content.length() > 50){
content = content.substring(0, 50) + "...";
}
blog.setContent(content);
blog.setUserId(resultSet.getShort("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
blogs.add(blog);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return blogs;
}
public Blog selectOne(int blogId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try{
connection = DBUtil.getConnection();
String sql = "select * from blog where blogId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,blogId);
resultSet = statement.executeQuery();
if(resultSet.next()){
Blog blog = new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
blog.setContent(resultSet.getString("content"));
blog.setUserId(resultSet.getShort("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
return blog;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
public void delete(int blogId){
Connection connection = null;
PreparedStatement statement = null;
try{
connection = DBUtil.getConnection();
String sql = "delete from blog where blogId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1, blogId);
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
}
通过jdbc中的查询和增加方法,实现通过用户名查询用户和根据用户id查询用户
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDao {
public User selectByName(String username){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select * from user where username = ?";
statement = connection.prepareStatement(sql);
statement.setString(1,username);
resultSet = statement.executeQuery();
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;
}
public User selectById(int userId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select * from user where userId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1, userId);
resultSet = statement.executeQuery();
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;
}
}
实现get方法,以json的数据格式返回数据,如果参数中没有blogid,则返回所有博客的信息,如果有blogid则返回对应的一篇博客
实现post方法,先通过session中数据判断是否登陆,若未登陆则强制要求登陆,再判断前端传输过来的的博客是否有题目和内容,若没有则返回,若符合规范,则调用BlogDao中的插入方法,将新的博客插入到数据库中
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json; charset=utf8");
String param = req.getParameter("blogId");
BlogDao blogDao = new BlogDao();
if(param == null){
//博客列表
List<Blog> blogs = blogDao.selectAll();
String respJson = objectMapper.writeValueAsString(blogs);
resp.getWriter().write(respJson);
} else {
//博客详情
int blogId = Integer.parseInt(param);
Blog blog = blogDao.selectOne(blogId);
String respJson = objectMapper.writeValueAsString(blog);
resp.getWriter().write(respJson);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false);
if(session == null){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登陆,请登陆后提交博客");
return;
}
User user = (User) session.getAttribute("user");
if(user == null){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登陆,请登陆后提交博客");
return;
}
req.setCharacterEncoding("utf8");
String title = req.getParameter("title");
String content = req.getParameter("content");
if(title == null || title.equals("") || content == null || content.equals("")){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("提交博客失败,缺少参数");
return;
}
Blog blog = new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setUserId(user.getUserId());
BlogDao blogDao = new BlogDao();
blogDao.insert(blog);
resp.sendRedirect("blogList.html");
}
}
实现get方法,先判定用户是否登陆,再判断博客中的参数是否存在,判断博客的用户id和用户的id是否一致(判断是否操作者为文章作者),全部确定为真时,调用BlogDao中的blogDelete方法,实现博客的删除功能
package controller;
import model.Blog;
import model.BlogDao;
import model.User;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/blogDelete")
public class BlogDeleteServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false);
if(session == null){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前尚未登录,无法删除!!");
return;
}
User user = (User) session.getAttribute("user");
if(user == null){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前尚未登录,无法删除!!");
return;
}
String blogId = req.getParameter("blogId");
if(blogId == null || blogId.equals("")){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前blogId参数错误!!");
return;
}
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
if(blog == null){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前要删除的博客不存在!!");
return;
}
if(user.getUserId() != blog.getUserId()){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前登陆用户无访问权限!!");
return;
}
blogDao.delete(Integer.parseInt(blogId));
resp.sendRedirect("blogList.html");
}
}
实现get方法,判断是否传输了blogid,判断blogid在数据库中是否存在,然后通过这个blogid,调用blogDao中的select方法,拿到blog对象,将密码设置为空(保护用户隐私),然后将用户信息以json格式传输给后端
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;
import model.UserDao;
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("/authorInfo")
public class AuthorServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json; charset=utf8");
String param = req.getParameter("blogId");
if(param == null || param.equals("")){
resp.getWriter().write("{\"ok\": false, \"reason \": \"参数缺失!\"}");
return;
}
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(param));
if(blog == null){
resp.getWriter().write("{\"ok\": false, \"reason \": \"查询的博客不存在!\"}");
return;
}
UserDao userDao = new UserDao();
User author = userDao.selectById(blog.getUserId());
if(author == null){
resp.getWriter().write("{\"ok\": false, \"reason \": \"查询的用户不存在!\"}");
return;
}
author.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(author));
}
}
实现post方法,获取前端传输的用户名和密码,判断是否符合规范,用UserDao中的select方法查询用户是否存在,如果存在则用user对象构造session,最后重定向到blogList.html
实现get方法,获取sessoin,将其转换为user对象,然后将其以json数据格式传输给前端
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.User;
import model.UserDao;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf8");
resp.setCharacterEncoding("utf8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if(username == null || username.equals("") || password == null || password.equals("")) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("输入用户名/密码为空!!!");
return;
}
UserDao userDao = new UserDao();
User user = userDao.selectByName(username);
if(user == null || !user.getPassword().equals(password)){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("用户名不存在/密码错误!!!");
return;
}
HttpSession session = req.getSession(true);
session.setAttribute("user",user);
resp.sendRedirect("blogList.html");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
HttpSession session = req.getSession(false);
if(session == null){
User user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
User user = (User) session.getAttribute("user");
if(user == null){
user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
user.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(user));
}
}
实现get方法,拿到session,通过是否为空判断用户是否登陆,如果登陆了,则移除该session,然后重定向到login.html
package controller;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false);
if(session == null){
resp.getWriter().write("当前用户尚未登录,无法注销!");
return;
}
session.removeAttribute("user");
resp.sendRedirect("login.html");
}
}
在之前的博客中有前端的代码,改动的地方如下
实现changeUserName的方法,获取页面左侧的用户名对应的h3标签,将其内容设置为当前登陆的用户的用户名
实现getUserInfo方法,参数是页名,类型是get方法,url是login,对应LoginServlet中的get方法。其功能是判断用户是否曾路,如果登陆了,就调用changeUserName方法,传输用户的名字
function getUserInfo(pageName){
$.ajax({
type: 'GET',
url: 'login',
success: function(body) {
if(body.userId && body.userId > 0){
console.log("登录成功! 用户名:" + body.username);
if(pageName == 'blogList.html'){
changeUserName(body.username);
}
} else {
alert("当前未登陆!!!");
location.assign('login.html');
}
},
error: function(){
alert("当前未登陆!!!");
location.assign('login.html');
}
});
}
function changeUserName(username){
let h3 = document.querySelector('.card>h3');
h3.innerHTML = username;
}
用户名,密码,提交按钮用form表单包裹,action是login,对应LoginServlet,method则是post方法,将用户名,密码增加id属性,并且将提交改成submit
<form action="login" method="POST">
<div class="row">
<span>用户名span>
<input type="text" id = 'username' name = 'username'>
div>
<div class="row">
<span>密码span>
<input type="password" id = 'password' name = 'password'>
div>
<div class="row submitRow">
<input type="submit" id = "submit" value = "提交">
div>
form>
<script>
function getBlogList(){
$.ajax({
type: 'get',
url: 'blog',
success: function(body) {
let rightDiv = document.querySelector('.right');
rightDiv.innerHTML = "";
for(let blog of body){
//blog
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.className = 'summary';
descDiv.innerHTML =blog.content;
blogDiv.appendChild(descDiv);
//查看全文
let a = document.createElement('a');
a.className = 'detail'
a.innerHTML = '查看全文 >>';
a.href = 'blogDetail.html?blogId=' + blog.blogId;
blogDiv.appendChild(a);
rightDiv.appendChild(blogDiv);
}
},
error: function(){
alert("获取博客失败!!!");
}
});
}
getBlogList();
script>
<script src="js/common.js">script>
<script>
getUserInfo('blogList.html');
script>
将script中加入saveHTMLToTextarea: true的属性,将html中的标题,发布按钮和内容改成下面对应的格式,外面使用form表单包裹,action是blog,方法是post,对应BlogServlet中的post方法,实现博客编辑后提交给服务器,服务器传输给数据库的功能
<form action="blog" method="POST" style="height:100%">
<div class="title">
<input type="text" placeholder = "在此输入标题" id = 'title' name = "title">
<input type="submit" value="发布文章" id="submit">
div>
<div id="editor">
<textarea name="content" style="display:none;">textarea>
div>
form>
<script>
var editor = editormd("editor", {
width:"100%",
height:"calc(100% - 80px)",
markdown:"# 在这里写下一篇博客",
path:"editor.md/lib/",
saveHTMLToTextarea: true
});
script>
用ajax实现getBlogDetail方法,类型为get,url为blog+location.search,对应后端的BlogServlet中的get方法,实现通过blogid获取blog对象功能,成功时将后端传输过来的blog对象中的题目,时间,内容等添加到dom树上
用ajax实现getAuthorInfo的方法,类型为get,url为authorInfo+location.search,对应AuthorServlet中的get方法,从前端获得登陆的用户信息,如果登陆的用户和文章的用户名相同,代表这个人可以删除自己的文章,在dom树上加删除的a标签,a标签中是blogDelete + location.search,对应后端的BlogDeleteServlet,实现将文章id传输给后端,后端让数据库删除该文章的操作
用ajax实现getUserInfo功能,大体功能和common.js中的getUserInfo功能大体相同,只是在其中调用getAuthorInfo方法
<script>
function getBlogDetail(){
$.ajax({
type: 'get',
url: 'blog' + location.search,
success: function(body){
let h3 = document.querySelector(".blogContainer>h3");
h3.innerHTML = body.title;
let dateDiv = document.querySelector('.date');
dateDiv.innerHTML = body.postTime;
editormd.markdownToHTML('content', {
markdown: body.content
});
}
});
}
getBlogDetail();
function getUserInfo(pageName){
$.ajax({
type: 'GET',
url: 'login',
success: function(body) {
if(body.userId && body.userId > 0){
console.log("登录成功! 用户名:" + body.username);
getAuthorInfo(body);
} else {
alert("当前未登陆!!!");
location.assign('login.html');
}
},
error: function(){
alert("当前未登陆!!!");
location.assign('login.html');
}
});
}
getUserInfo('blogDetail.html');
function getAuthorInfo(user){
$.ajax({
type: 'GET',
url: 'authorInfo' + location.search,
success: function(body){
if(body.username){
changeUserName(body.username);
if(body.username == user.username){
let navDiv = document.querySelector('.nav');
let a = document.createElement('a');
a.innerHTML = '删除';
a.href = 'blogDelete' + location.search;
navDiv.appendChild(a);
}
} else {
console.log("获取作者信息失败!!!" + body.reason);
}
}
});
}
function changeUserName(username){
let h3 = document.querySelector('.card>h3');
h3.innerHTML = username;
}
script>