国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

博客系統(tǒng)(前后端分離)

這篇具有很好參考價(jià)值的文章主要介紹了博客系統(tǒng)(前后端分離)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

??作者:銀河罐頭
??系列專欄:JavaEE

??“種一棵樹最好的時(shí)間是十年前,其次是現(xiàn)在”

準(zhǔn)備工作

創(chuàng)建項(xiàng)目,引入依賴,把之前寫的前端頁(yè)面拷貝進(jìn)去。

依賴主要是:servlet, mysql, jackson

博客系統(tǒng)(前后端分離)

數(shù)據(jù)庫(kù)設(shè)計(jì)

表設(shè)計(jì)

在當(dāng)前的博客系統(tǒng)中,主要涉及到 2 個(gè)實(shí)體,博客 和 用戶。

創(chuàng)建 2 張表,來(lái)表示博客和用戶。用戶和博客之間的關(guān)系是一對(duì)多。

博客系統(tǒng)(前后端分離)

把一些基本的數(shù)據(jù)庫(kù)操作先封裝好,以備后用。

-- 這個(gè)文件主要寫建庫(kù)建表語(yǔ)句
-- 建議 在建表的時(shí)候把 sql 語(yǔ)句保留下來(lái),以便后續(xù)部署其他機(jī)器的時(shí)候就方便了。

create database if not exists java_blog_system;
use java_blog_system;
-- 刪除舊表,重新創(chuàng)建新表
drop table if exists user;
drop table if exists blog;

-- 真正創(chuàng)建表
create table blog(
    blogId int primary key auto_increment,
    title varchar(128),
    content varchar(4096),
    postTime datetime,
    useId int
);

create table user(
    userId int primary key auto_increment,
    username varchar(20) unique, -- 要求用戶名和別人不重復(fù)
    password varchar(20)
);

封裝數(shù)據(jù)庫(kù)的連接操作

public class DBUtil {
    private static DataSource dataSource = new MysqlDataSource();
    static {
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java_blog_system?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("123456");
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.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();
            }
        }
    }
}

創(chuàng)建實(shí)體類

實(shí)體類,和表中記錄對(duì)應(yīng)的類。

blog 表,Blog 類對(duì)應(yīng)。Blog 的一個(gè)對(duì)象,就對(duì)應(yīng)表中的一條記錄。

user 表,User 類對(duì)應(yīng)。User 的一個(gè)對(duì)象,就對(duì)應(yīng)表中的一條記錄。

實(shí)體類里要有哪些屬性,是和表里的列是密切相關(guān)的。

public class Blog {
    private int blogId;
    private String title;
    private String content;
    private Timestamp postTime;
    private int userId;

    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 Timestamp getPostTime() {
        return postTime;
    }

    public void setPostTime(Timestamp postTime) {
        this.postTime = postTime;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }
}
public class User {
    private int userId;
    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;
    }
}

封裝數(shù)據(jù)庫(kù)的增刪改查

針對(duì)博客表,創(chuàng)建 BlogDao

針對(duì)用戶表,創(chuàng)建 UserDao

提供一些方法,來(lái)進(jìn)行增刪改查。

Dao, Data Access Object 訪問數(shù)據(jù)的對(duì)象

//通過這個(gè)類,封裝對(duì)博客表的基本操作
public class BlogDao {
    //1.新增一個(gè)博客
    public void add(Blog blog) {

    }
    //2.根據(jù) 博客 id 來(lái)查詢博客(博客詳情頁(yè)中)
    public Blog selectById(int blogId){
        return null;
    }
    //3.查詢出數(shù)據(jù)庫(kù)中所有的博客列表(博客列表頁(yè))
    public List<Blog> selectAll(){
        return null;
    }
    //4.刪除指定博客
    public void delete(int blogId){

    }
}

博客系統(tǒng)(前后端分離)

//通過這個(gè)類,封裝對(duì)博客表的基本操作
public class BlogDao {
    //1.新增一個(gè)博客
    public void add(Blog blog) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1.建立連接
            connection = DBUtil.getConnection();
            //2.構(gòu)造 sql
            String sql = "insert into blog values(null, ?, ?, ?, ?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1, blog.getTitle());
            statement.setString(2,blog.getContent());
            statement.setTimestamp(3,blog.getPostTime());
            statement.setInt(4,blog.getUserId());
            //3.執(zhí)行 sql
            statement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4.斷開連接,釋放資源
            DBUtil.close(connection, statement, null);
        }
    }
    //2.根據(jù) 博客 id 來(lái)查詢博客(博客詳情頁(yè)中)
    public Blog selectById(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1.和數(shù)據(jù)庫(kù)建立連接
            connection = DBUtil.getConnection();
            //2.構(gòu)造 SQL
            String sql = "select * from blog while blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3.執(zhí)行 SQL
            resultSet = statement.executeQuery();
            //4.遍歷結(jié)果集合
            //blogId 是自增主鍵,是唯一的。所以要么是沒有查到,要么是查到了一條記錄
            //此處可以不使用 where, 直接 if 判定即可
            if (resultSet.next()){
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                blog.setContent(resultSet.getString("content"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));
                return blog;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //5.釋放資源,斷開連接
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
    //3.查詢出數(shù)據(jù)庫(kù)中所有的博客列表(博客列表頁(yè))
    public List<Blog> selectAll(){
        List<Blog> blogs = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1.建立連接
            connection = DBUtil.getConnection();
            //2.構(gòu)造 SQL 語(yǔ)句
            String sql = "select * from blog";
            statement = connection.prepareStatement(sql);
            //3.執(zhí)行 sql 語(yǔ)句
            statement.executeQuery();
            //4.遍歷結(jié)果集合
            while(resultSet.next()){
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                //注意這里的正文,博客列表頁(yè)不需要把整個(gè)正文都顯示出來(lái)
                String content = resultSet.getString("content");
                if(content.length() >= 100){
                    content = content.substring(0,100) + "...";
                }
                blog.setContent(content);
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blog.setUserId(resultSet.getInt("userId"));
                blogs.add(blog);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection, statement, resultSet);

        }
        return blogs;
    }
    //4.刪除指定博客
    public void delete(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1.建立連接
            connection = DBUtil.getConnection();
            //2.構(gòu)建 SQL 語(yǔ)句
            String sql = "delete from blog while blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3.執(zhí)行 sql
            statement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4.關(guān)閉連接
            DBUtil.close(connection,statement,null);
        }
    }
}
//針對(duì)用戶表提供的基本操作
//由于沒寫注冊(cè)功能,此處就不寫 add 了
//也沒有用戶刪號(hào)這個(gè)功能,也就不必 delete
public class UserDao {
    //根據(jù) userId 來(lái)查用戶信息
    public User selectById(int userId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1.建立連接
            connection = DBUtil.getConnection();
            //2.構(gòu)造 SQL
            String sql = "select * from user where userId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,userId);
            //3.執(zhí)行 sql
            resultSet = statement.executeQuery();
            //4.遍歷結(jié)果集
            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;
    }
    //根據(jù) username 來(lái)查用戶信息(登錄的時(shí)候)
    public User selectByUsername(String username){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1.建立連接
            connection = DBUtil.getConnection();
            //2.構(gòu)造 SQL
            String sql = "select * from user where username = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1,username);
            //3.執(zhí)行 sql
            resultSet = statement.executeQuery();
            //4.遍歷結(jié)果集
            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;
    }
}

實(shí)現(xiàn)博客列表頁(yè)

當(dāng)前博客列表頁(yè)上的數(shù)據(jù)都是寫死的,正確的做法應(yīng)該是從服務(wù)器獲取數(shù)據(jù)并顯示到頁(yè)面上。

讓博客列表頁(yè),加載的時(shí)候,通過 ajax 給服務(wù)器發(fā)一個(gè)請(qǐng)求,服務(wù)器查數(shù)據(jù)庫(kù)獲取博客列表數(shù)據(jù),返回給瀏覽器,瀏覽器根據(jù)數(shù)據(jù)構(gòu)造頁(yè)面內(nèi)容。

這樣的交互過程,稱為 “前后端分離”。

前端只是向后端索要數(shù)據(jù),而不是請(qǐng)求具體的頁(yè)面。后端也僅僅是返回?cái)?shù)據(jù)。

這樣設(shè)定的目的就是讓前端和后端更加解耦。

由瀏覽器進(jìn)行具體的頁(yè)面渲染,減少了服務(wù)器的工作量。

上述是實(shí)現(xiàn)博客列表頁(yè)的基本思路。

接下來(lái)需要:

1.約定前后端交互接口

獲取博客列表功能,前端要發(fā)啥請(qǐng)求,后端要返回啥響應(yīng)。

2.開發(fā)后端代碼

3.開發(fā)前端代碼

約定前后端交互接口

博客系統(tǒng)(前后端分離)

開發(fā)后端代碼

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BlogDao blogDao = new BlogDao();
        List<Blog> blogs = blogDao.selectAll();
        //需要 把 blogs 轉(zhuǎn)成符合要求的 json 字符串
        String respJson = objectMapper.writeValueAsString(blogs);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(respJson);
    }
}

博客系統(tǒng)(前后端分離)

把 servlet 放到 api 包里,api 不一定非得是 類/方法,也可以是 “網(wǎng)絡(luò)請(qǐng)求”(處理 http 請(qǐng)求,返回 http 響應(yīng))

開發(fā)前端代碼

在博客列表頁(yè)加載過程中,通過 ajax 訪問服務(wù)器數(shù)據(jù),再把拿到的數(shù)據(jù)構(gòu)造到頁(yè)面中。

博客系統(tǒng)(前后端分離)

<script src="./js/jquery.min.js"></script>
    <script>
        //在頁(yè)面加載的時(shí)候,向服務(wù)器發(fā)起請(qǐng)求,獲取博客列表數(shù)據(jù)
        function getBlogs() {
            $.ajax({
                type:'get',
                url: 'blog',
                success: function(body) {
                    //響應(yīng)的正文是 json 字符串,已經(jīng)被 jquery 自動(dòng)解析成 js 對(duì)象數(shù)組了
                    // for 循環(huán)遍歷即可
                    let containerRight = document.querySelector('.container-right');
                    for(let blog of body){
                        //構(gòu)造頁(yè)面內(nèi)容,參考之前寫好的 html 代碼
                        //構(gòu)造整個(gè)博客 div
                        let blogDiv = document.createElement('div');
                        blogDiv.className = 'blog';
                        //構(gòu)造 標(biāo)題
                        let titleDiv = document.createElement('div');
                        titleDiv.className = 'title';
                        titleDiv.innerHTML = blog.title;
                        blogDiv.appendChild(titleDiv);
                        //構(gòu)造發(fā)布時(shí)間
                        let dateDiv = document.createElement('div');
                        dateDiv.className = 'date';
                        dateDiv.innerHTML = blog.postTime;
                        blogDiv.appendChild(dateDiv);
                        //構(gòu)造博客摘要
                        let descDiv = document.createElement('div');
                        descDiv.className = 'desc';
                        descDiv.innerHTML = blog.content;
                        blogDiv.appendChild(descDiv);
                        //構(gòu)造查看全文按鈕
                        let a = document.createElement('a');
                        a.innerHTML = '查看全文 &gt;&gt;';
                        //希望點(diǎn)擊之后能跳轉(zhuǎn)到博客詳情頁(yè)
                        //為了讓博客詳情頁(yè)知道是點(diǎn)了哪個(gè)博客,把 blogId 傳過去
                        a.href = 'blog_detail.html?blogId=' + blog.blogId;
                        blogDiv.appendChild(a);

                        //把 blogDiv 加到父元素中
                        containerRight.appendChild(blogDiv);
                    }
                }
            });
        }
        //記得調(diào)用函數(shù)
        getBlogs();
    </script>

此時(shí),博客列表頁(yè)實(shí)現(xiàn)完成。

博客系統(tǒng)(前后端分離)

此時(shí)看的的博客列表頁(yè)是空著的,因?yàn)椴┛土斜淼臄?shù)據(jù)來(lái)自于數(shù)據(jù)庫(kù),而現(xiàn)在數(shù)據(jù)庫(kù)是空著的。

博客系統(tǒng)(前后端分離)

-- 構(gòu)造測(cè)試數(shù)據(jù)
insert into blog values(1, '這是我的第一篇博客', '從今天開始我要認(rèn)真敲代碼', now(),1);
insert into blog values(2, '這是我的第二篇博客', '從昨天開始我要認(rèn)真敲代碼', now(),1);
insert into blog values(3, '這是我的第三篇博客', '從前天開始我要認(rèn)真敲代碼', now(),1);

此處只是把 idea 當(dāng)做是個(gè) 記事本,來(lái)記錄下 sql 而已。真正要執(zhí)行,要復(fù)制到 sql 客戶端里執(zhí)行。

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

有 2 個(gè) bug,

1.不應(yīng)該顯示時(shí)間戳,而應(yīng)該顯示格式化時(shí)間

需要用到一個(gè) 格式化時(shí)間的類,轉(zhuǎn)換一下。

SimpleDateFormat

博客系統(tǒng)(前后端分離)

public Timestamp getPostTimestamp() {
    return postTime;
}

public String getPostTime(){
    //把時(shí)間戳轉(zhuǎn)換成格式化時(shí)間
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    return simpleDateFormat.format(postTime);
}

2.順序,新的博客在上面,老的博客在下面。

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

實(shí)現(xiàn)博客詳情頁(yè)

接下來(lái)實(shí)現(xiàn)博客詳情頁(yè),點(diǎn)擊"查看全文"按鈕,就能跳轉(zhuǎn)到博客詳情頁(yè)中。跳轉(zhuǎn)之后,在博客詳情頁(yè)中,對(duì)服務(wù)器發(fā)起 ajax 請(qǐng)求,從服務(wù)器獲取數(shù)據(jù),然后顯示出來(lái)。

博客系統(tǒng)(前后端分離)

約定前后端交互接口

博客系統(tǒng)(前后端分離)

開發(fā)后端代碼

博客系統(tǒng)(前后端分離)

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BlogDao blogDao = new BlogDao();
        //嘗試獲取下 query string 中的 blogId字段
        String blogId = req.getParameter("blogId");
        if (blogId == null) {
            //說(shuō)明 query string 不存在,說(shuō)明這次請(qǐng)求是在獲取博客列表頁(yè)

            List<Blog> blogs = blogDao.selectAll();
            //需要 把 blogs 轉(zhuǎn)成符合要求的 json 字符串
            String respJson = objectMapper.writeValueAsString(blogs);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        } else {
            //說(shuō)明 query string 存在,說(shuō)明這次請(qǐng)求是在獲取博客詳情頁(yè)
            Blog blog = blogDao.selectById(Integer.parseInt(blogId));
            if(blog == null) {
                System.out.println("當(dāng)前 blogId = " + blogId + " 對(duì)應(yīng)的博客不存在!");
            }
            String respJson = objectMapper.writeValueAsString(blog);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        }
    }
}

開發(fā)前端代碼

在 blog_datail.html 中,加入 ajax,來(lái)獲取數(shù)據(jù)。

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

<script src="js/jquery.min.js"></script>
<!-- 保證 這幾個(gè) js 的加載要在 jquery 之后,因?yàn)?edit.md 依賴 jquery-->
<script src="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.js"></script>
<script>
    $.ajax({
    type: 'get',
    url: 'blog' + location.search,
    success: function(body) {//回調(diào)函數(shù)
        //處理響應(yīng)結(jié)果,此處的 body 就表示一個(gè)博客的 js 對(duì)象
        //1.更新標(biāo)題
        let titleDiv = document.querySelector('.title');
        titleDiv.innerHTML = body.title;
        //2.更新日期
        let dateDiv = document.querySelector('.date');
        dateDiv.innerHTML = body.postTime;
        //3.更新博客正文
        //此處不應(yīng)該直接把博客內(nèi)容填充到標(biāo)簽里
        editormd.markdownToHTML('content',{ markdown: blog.content });
    }
});
</script>

博客系統(tǒng)(前后端分離)

代碼改完之后,重新啟動(dòng)服務(wù)器,發(fā)現(xiàn)此時(shí)博客詳情頁(yè)的結(jié)果還是之前未修改的狀態(tài)。

博客系統(tǒng)(前后端分離)

始端用戶訪問加速節(jié)點(diǎn)時(shí),如果該節(jié)點(diǎn)有緩存住了要被訪問的數(shù)據(jù)時(shí)就叫做命中,如果沒有的話需要回原服務(wù)器取,就是沒有命中。

博客系統(tǒng)(前后端分離)

緩沖問題解決了,但是頁(yè)面仍然不是預(yù)期的效果。

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

修改上述代碼之后,發(fā)現(xiàn)正文有了,但是標(biāo)題沒出來(lái)。

就需要抓包,看下服務(wù)器返回結(jié)果是否符合預(yù)期,就可以確定是前端問題還是后端問題了。

博客系統(tǒng)(前后端分離)

響應(yīng)結(jié)果是正確的,后端代碼應(yīng)該沒問題。

接下來(lái)檢查前端代碼。

博客系統(tǒng)(前后端分離)

解決方案,把選擇器寫的更準(zhǔn)確一些。

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

實(shí)現(xiàn)博客登錄頁(yè)

博客系統(tǒng)(前后端分離)

此處輸入用戶名,密碼,點(diǎn)擊登錄,就會(huì)觸發(fā)一個(gè) http 請(qǐng)求。服務(wù)器驗(yàn)證用戶名和密碼,如果登陸成功,就跳轉(zhuǎn)到博客列表頁(yè)。

當(dāng)前還只是一個(gè) 輸入框,還不能提交請(qǐng)求,需要給改成 form 表單。

約定前后端交互接口

博客系統(tǒng)(前后端分離)

開發(fā)前端代碼

在頁(yè)面里加上 form 表單,使點(diǎn)擊登錄操作能 觸發(fā)請(qǐng)求。

<!-- 垂直水平居中的登錄對(duì)話框 -->
<div class="login-dialog">
    <form action="login" method="post">
        <h3>登錄</h3>
        <div class="row">
            <span>用戶名</span>
            <input type="text" id="username" placeholder="手機(jī)號(hào)/郵箱" name="username">
        </div>
        <div class="row">
            <span>密碼</span>
            <input type="password" id="password" name="password">
        </div>
        <div class="row">
            <input type="submit" id="submit" value="登錄">
        </div>
    </form>
</div>

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

請(qǐng)求已經(jīng)構(gòu)造出來(lái)了。

開發(fā)后端代碼

此處需要價(jià)格 servlet 來(lái)處理 登錄請(qǐng)求。

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //設(shè)置請(qǐng)求的編碼,告訴 servlet 按照啥格式理解請(qǐng)求
        req.setCharacterEncoding("utf8");
        //設(shè)置響應(yīng)的編碼,告訴 servlet 以啥樣的格式構(gòu)造響應(yīng)
//        resp.setCharacterEncoding("utf8");
        resp.setContentType("text/html;charset=utf8");
        //1.讀取參數(shù)中的用戶名,密碼
        //注意,如果用戶名密碼中存在中文,這里讀取可能會(huì)亂碼
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if(username == null || "".equals(username) || password == null || "".equals(password)){
            //登陸失敗!
            String html = "<h3> 登錄失?。?缺少 username 或者 password 字段 </h3>";
            resp.getWriter().write(html);
            return;
        }
        //2.讀一下數(shù)據(jù)庫(kù),看用戶名是否存在,密碼是否匹配
        UserDao userDao = new UserDao();
        User user = userDao.selectByUsername(username);
        if(user == null){
            //用戶不存在
            String html = "<h3> 登錄失??! 用戶名或密碼錯(cuò)誤 </h3>";
            resp.getWriter().write(html);
            return;
        }
        if(!password.equals(user.getPassword())){
            //密碼錯(cuò)誤
            String html = "<h3> 登錄失??! 用戶名或密碼錯(cuò)誤 </h3>";
            resp.getWriter().write(html);
            return;
        }
        //3.用戶名密碼驗(yàn)證通過,登陸成功,接下來(lái)創(chuàng)建會(huì)話,使用該會(huì)話保存用戶信息
        HttpSession session = req.getSession(true);
        session.setAttribute("username", username);
        //4.進(jìn)行重定向,跳轉(zhuǎn)到博客列表頁(yè)
        resp.sendRedirect("blog_list.html");
    }
}

這樣還是無(wú)法登錄成功,因?yàn)閿?shù)據(jù)庫(kù)沒有保存用戶名密碼。

博客系統(tǒng)(前后端分離)

構(gòu)造一些測(cè)試數(shù)據(jù),保存到數(shù)據(jù)庫(kù)里。

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

登陸成功。

實(shí)現(xiàn)強(qiáng)制要求登陸

當(dāng)用戶訪問博客列表頁(yè)/詳情頁(yè)/編輯頁(yè),要求用戶必須是已登錄的狀態(tài),如果用戶還沒有登錄,就會(huì)強(qiáng)制跳轉(zhuǎn)到登錄頁(yè)面。

博客系統(tǒng)(前后端分離)

約定前后端交互接口

博客系統(tǒng)(前后端分離)

開發(fā)后端代碼

博客系統(tǒng)(前后端分離)

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType("application/json;charset=utf8");
    //使用這個(gè)方法來(lái)獲取用戶的登錄狀態(tài)
    HttpSession session = req.getSession(false);
    if(session == null){
        User user = new User();
        String respJson = objectMapper.writeValueAsString(user);
        resp.getWriter().write(respJson);
        return;
    }
    User user = (User)session.getAttribute("user");
    if(user == null){
        user = new User();
        String respJson = objectMapper.writeValueAsString(user);
        resp.getWriter().write(respJson);
        return;
    }
    //確實(shí)取出了 user 對(duì)象,直接返回即可
    String respJson = objectMapper.writeValueAsString(user);
    resp.getWriter().write(respJson);
}

開發(fā)前端代碼

博客系統(tǒng)(前后端分離)

function checkLogin() {
    $.ajax({
        type: 'get',
        url: 'login',
        success: function(body) {
            if(body.userId && body.userId > 0){
                //登陸成功
                console.log("當(dāng)前用戶已登錄!");
            } else {
                //當(dāng)前未登錄,強(qiáng)制跳轉(zhuǎn)到登錄頁(yè)
                location.assign('blog_login.html');
            }
        }
    });
}
checkLogin();

把這段代碼加到 列表頁(yè),詳情頁(yè),編輯頁(yè)的代碼中。

重啟服務(wù)器之后,之前的登錄狀態(tài)就沒了。

博客系統(tǒng)(前后端分離)

實(shí)現(xiàn)顯示用戶信息

目前頁(yè)面的用戶信息部分是寫死的.

博客系統(tǒng)(前后端分離)

這個(gè)地方時(shí)寫死的,希望能夠動(dòng)態(tài)生成。

1.如果是博客列表頁(yè),此處顯示登錄用戶的信息。

2.如果是博客詳情頁(yè),此處顯示該文章的作者。

比如我以"張三"的身份登錄,查看博客列表頁(yè)時(shí),左側(cè)應(yīng)該顯示"張三"的用戶信息,然后我點(diǎn)開李四寫的博客,跳轉(zhuǎn)到博客詳情頁(yè),應(yīng)該顯示作者"李四"的信息。

約定前后端交互接口

博客系統(tǒng)(前后端分離)

列表頁(yè)

function checkLogin() {
    $.ajax({
        type: 'get',
        url: 'login',
        success: function(body) {
            if(body.userId && body.userId > 0){
                //登陸成功
                console.log("當(dāng)前用戶已登錄!");
                //把當(dāng)前用戶的名字顯示到界面上
                let h3 = document.querySelector('.container-left .card h3');
                h3.innerHTML = body.username;
            } else {
                //當(dāng)前未登錄,強(qiáng)制跳轉(zhuǎn)到登錄頁(yè)
                location.assign('blog_login.html');
            }
        }
    });
}

博客系統(tǒng)(前后端分離)

詳情頁(yè)

@WebServlet("/author")
public class AuthorServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String blogId = req.getParameter("blogId");
        if(blogId == null){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("參數(shù)非法,缺少 blogId");
            return;
        }
        //根據(jù) blogId 查詢 Blog 對(duì)象
        BlogDao blogDao = new BlogDao();
        Blog blog = blogDao.selectById(Integer.parseInt(blogId));
        if(blog == null){
            //博客不存在
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("沒有找到指定博客: blogId = " + blogId);
            return;
        }
        //根據(jù) Blog 中的 userId 找到 用戶信息
        UserDao userDao = new UserDao();
        User author = userDao.selectById(blog.getUserId());
        String respJson = objectMapper.writeValueAsString(author);
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write(respJson);
    }
}
function getAuthor() {
    $.ajax({
        type: 'get',
        url: 'author',
        success: function(body) {
            //把 username 設(shè)置到界面上
            let h3 = document.querySelector('.container-left .card h3');
            h3.innerHTML = body.username;
        }
    });
}
getAuthor();

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

抓包后發(fā)現(xiàn)是少了 query string.

改下前端代碼。

function getAuthor() {
    $.ajax({
        type: 'get',
        url: 'author' + location.search,
        success: function(body) {
            //把 username 設(shè)置到界面上
            let h3 = document.querySelector('.container-left .card h3');
            h3.innerHTML = body.username;
        }
    });
}
getAuthor();

博客系統(tǒng)(前后端分離)

退出登錄狀態(tài)

注銷(sign out)

判定登錄狀態(tài):

1.看是否能查到 http session 對(duì)象;

2.看 session 對(duì)象里有沒有 user 對(duì)象

博客系統(tǒng)(前后端分離)

實(shí)現(xiàn)退出登錄,要么把 session 干掉,要么把 user 干掉。只要干掉一個(gè)就可以。

HttpSession 對(duì)象要想干掉,麻煩點(diǎn)。getSession 能夠創(chuàng)建/獲取會(huì)話,沒有刪除會(huì)話的方法。直接刪除還不好刪,可以通過設(shè)置會(huì)話的過期時(shí)間來(lái)達(dá)到類似的效果,但并不優(yōu)雅。

更好的辦法是把 user 干掉,通過 removeAttribute 就刪了。

之前的邏輯中, httpSession 和 user 是一榮俱榮一損俱損的情況,但是引入注銷邏輯后,就出現(xiàn)有 httpSession 沒 user 的情況。

明確思路之后,先設(shè)計(jì)前后端交互接口。

約定前后端交互接口

博客系統(tǒng)(前后端分離)

博客系統(tǒng)(前后端分離)

開發(fā)后端代碼

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession httpSession = req.getSession(false);
        if(httpSession == null){
            //未登錄,提示出錯(cuò)
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("當(dāng)前未登錄!");
            return;
        }
        httpSession.removeAttribute("user");
        resp.sendRedirect("login.html");
    }
}

開發(fā)前端代碼

把 blog_detail.html, blog_edit.html, blog_list.html 這幾個(gè)的 a 標(biāo)簽改下就行。

博客系統(tǒng)(前后端分離)

發(fā)布博客

博客系統(tǒng)(前后端分離)

寫博客寫了一些內(nèi)容,點(diǎn)擊"發(fā)布文章",沒有反應(yīng)。

約定前后端交互接口

博客系統(tǒng)(前后端分離)

開發(fā)后端代碼

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BlogDao blogDao = new BlogDao();
        //嘗試獲取下 query string 中的 blogId字段
        String blogId = req.getParameter("blogId");
        if (blogId == null) {
            //說(shuō)明 query string 不存在,說(shuō)明這次請(qǐng)求是在獲取博客列表頁(yè)

            List<Blog> blogs = blogDao.selectAll();
            //需要 把 blogs 轉(zhuǎn)成符合要求的 json 字符串
            String respJson = objectMapper.writeValueAsString(blogs);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        } else {
            //說(shuō)明 query string 存在,說(shuō)明這次請(qǐng)求是在獲取博客詳情頁(yè)
            Blog blog = blogDao.selectById(Integer.parseInt(blogId));
            if(blog == null) {
                System.out.println("當(dāng)前 blogId = " + blogId + " 對(duì)應(yīng)的博客不存在!");
            }
            String respJson = objectMapper.writeValueAsString(blog);
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write(respJson);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 發(fā)布博客
        //讀取請(qǐng)求,構(gòu)造 blog 對(duì)象,插入數(shù)據(jù)庫(kù)中
        HttpSession httpSession = req.getSession(false);
        if(httpSession == null){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("當(dāng)前未登錄,無(wú)法發(fā)布博客!");
            return;
        }
        User user = (User) httpSession.getAttribute("user");
        if(user == null){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("當(dāng)前未登錄,無(wú)法發(fā)布博客!");
            return;
        }
        //確保登陸之后,就可以把作者拿到了

        //獲取博客標(biāo)題和正文
        String title = req.getParameter("title");
        String content = req.getParameter("content");
        if(title == null || "".equals(title) || content == null || "".equals(content)){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("當(dāng)前提交數(shù)據(jù)有誤,標(biāo)題或正文為空!");
            return;
        }

        //構(gòu)造一個(gè) blog 對(duì)象
        Blog blog = new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        blog.setUserId(user.getUserId());
        //發(fā)布時(shí)間,在 java 中生成 / 在數(shù)據(jù)庫(kù)中生成都行
        blog.setPostTime(new Timestamp(System.currentTimeMillis()));
        //插入數(shù)據(jù)庫(kù)
        BlogDao blogDao = new BlogDao();
        blogDao.add(blog);
        //跳轉(zhuǎn)到博客列表頁(yè)
        resp.sendRedirect("blog_list.html");
    }
}

開發(fā)前端代碼

把頁(yè)面改造下,能夠構(gòu)造出請(qǐng)求。

博客系統(tǒng)(前后端分離)

<div class="blog-edit-container">
    <form action="blog" method="post">
        <!-- 博客標(biāo)題編輯區(qū) -->
        <div class="title">
            <input type="text" id="title" placeholder="輸入文章標(biāo)題" name="title">
            <input type="submit" id="submit" value="發(fā)布文章">
        </div>
        <!-- 博客編輯器, 這里用 id 是為了和 markdown 編輯器對(duì)接 -->
        <div id="editor">
            <textarea name="content" style="display: none;"></textarea>
        </div>
    </form>
</div>

博客系統(tǒng)(前后端分離)

代碼改完之后,再次運(yùn)行,發(fā)現(xiàn)只顯示一小段了。

前端代碼有問題,看 chrome 開發(fā)者工具。

博客系統(tǒng)(前后端分離)

之前給編輯器設(shè)置的高度。

博客系統(tǒng)(前后端分離)

<form action="blog" method="post" style="height: 100%;">

博客系統(tǒng)(前后端分離)

發(fā)現(xiàn)亂碼了?!

亂碼是提交博客的時(shí)候亂的,還是獲取博客的時(shí)候亂的?

這里大概率是提交的時(shí)候亂的,因?yàn)楂@取數(shù)據(jù)這個(gè)功能前面已經(jīng)測(cè)試過了,而提交這個(gè)功能還沒有測(cè)試過。

只要看下數(shù)據(jù)庫(kù)是不是亂的。

博客系統(tǒng)(前后端分離)

應(yīng)該是提交的時(shí)候就亂了。

把亂碼的第4條刪掉。

博客系統(tǒng)(前后端分離)

//獲取博客標(biāo)題和正文
req.setCharacterEncoding("utf8");
String title = req.getParameter("title");
String content = req.getParameter("content");

博客系統(tǒng)(前后端分離)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-412795.html

到了這里,關(guān)于博客系統(tǒng)(前后端分離)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Java EE】-博客系統(tǒng)一(前后端分離)

    【Java EE】-博客系統(tǒng)一(前后端分離)

    作者 :學(xué)Java的冬瓜 博客主頁(yè) :?冬瓜的主頁(yè)?? 專欄 :【JavaEE】 分享 : 謎一樣的 沉默著的 故事你真的在聽嗎 ——《平凡之路》 主要內(nèi)容 :準(zhǔn)備工作:創(chuàng)建maven,引入依賴。設(shè)計(jì)數(shù)據(jù)庫(kù)并編寫數(shù)據(jù)庫(kù)代碼。前后端分離功能的實(shí)現(xiàn)。博客列表,博客詳情,登錄功能,注冊(cè)功

    2024年02月12日
    瀏覽(24)
  • 【基于前后端分離的博客系統(tǒng)】Servlet版本

    【基于前后端分離的博客系統(tǒng)】Servlet版本

    ? ?????? 點(diǎn)進(jìn)來(lái)你就是我的人了 博主主頁(yè): ?????? 戳一戳,歡迎大佬指點(diǎn)! 歡迎志同道合的朋友一起加油喔 ?????? 目錄 一. 項(xiàng)目簡(jiǎn)介? 1. 項(xiàng)目背景 2. 項(xiàng)目用到的技術(shù) 3. 項(xiàng)目功能簡(jiǎn)單介紹? 二. 博客系統(tǒng)頁(yè)面設(shè)計(jì)? 三. 項(xiàng)目準(zhǔn)備工作 前后端交互約定內(nèi)容的分析? 1. 接口

    2024年02月08日
    瀏覽(22)
  • 【Java EE】-博客系統(tǒng)二(前后端分離)

    【Java EE】-博客系統(tǒng)二(前后端分離)

    作者 :學(xué)Java的冬瓜 博客主頁(yè) :?冬瓜的主頁(yè)?? 專欄 :【JavaEE】 分享 : 徘徊著的 在路上的 你要走嗎 易碎的 驕傲著 那也曾是我的模樣 ——《平凡之路》 主要內(nèi)容 :顯示用戶信息、上傳頭像、新增博客、刪除博客、修改博客。 分兩個(gè)子功能:列表頁(yè)顯示登錄用戶信息;

    2024年02月11日
    瀏覽(24)
  • SSM項(xiàng)目前后端分離+IDEA運(yùn)行環(huán)境(含前端源碼)(個(gè)人博客系統(tǒng))

    SSM項(xiàng)目前后端分離+IDEA運(yùn)行環(huán)境(含前端源碼)(個(gè)人博客系統(tǒng))

    目錄 ?后端項(xiàng)目環(huán)境配置 1、創(chuàng)建一個(gè)SpringBoot項(xiàng)目,添加MyBatis框架和數(shù)據(jù)庫(kù)MySQL驅(qū)動(dòng)依賴 2、配置項(xiàng)目文件:application.yml 3、創(chuàng)建數(shù)據(jù)庫(kù)表 4、創(chuàng)建分層結(jié)構(gòu)目錄 返回統(tǒng)一數(shù)據(jù)格式? 創(chuàng)建統(tǒng)一數(shù)據(jù)格式返回類:AjaxResult 創(chuàng)建實(shí)現(xiàn)統(tǒng)一數(shù)據(jù)返回的保底類:ResponseAdvice 統(tǒng)一處理 登錄

    2024年02月13日
    瀏覽(49)
  • 川西旅游網(wǎng)系統(tǒng)-前后端分離(前臺(tái)vue 后臺(tái)element UI,后端servlet)

    川西旅游網(wǎng)系統(tǒng)-前后端分離(前臺(tái)vue 后臺(tái)element UI,后端servlet)

    前臺(tái):tour_forword: 川西旅游網(wǎng)前端----前臺(tái) (gitee.com) 后臺(tái):tour_back: 川西旅游網(wǎng)-------后臺(tái) (gitee.com) 后端 :tour: 川西旅游網(wǎng)------后端 (gitee.com)

    2024年02月07日
    瀏覽(24)
  • 基于Java+MySQL+Tomcat+Servlet+Maven+JQuery+jackson+開源Markdown編輯器實(shí)現(xiàn)前后端分離個(gè)人博客系統(tǒng)

    基于Java+MySQL+Tomcat+Servlet+Maven+JQuery+jackson+開源Markdown編輯器實(shí)現(xiàn)前后端分離個(gè)人博客系統(tǒng)

    目錄 項(xiàng)目簡(jiǎn)介 模塊實(shí)現(xiàn) 設(shè)計(jì)實(shí)現(xiàn)數(shù)據(jù)庫(kù)相關(guān)代碼 博客列表頁(yè) 博客詳情頁(yè) 注冊(cè)頁(yè) 登錄頁(yè) 檢測(cè)登錄狀態(tài) 顯示用戶信息 退出登錄 發(fā)布博客 刪除博客 統(tǒng)計(jì)博客數(shù)量 效果展示 部分代碼展示 小結(jié): ? ? 項(xiàng)目中使用了Java ,MySQL ,Tomcat ,Servlet ,Maven ,JQuery ,jackson,開源MarkDo

    2024年02月02日
    瀏覽(17)
  • 博客項(xiàng)目(前后端分離)(servlet實(shí)戰(zhàn)演練)

    博客項(xiàng)目(前后端分離)(servlet實(shí)戰(zhàn)演練)

    作者簡(jiǎn)介:大家好,我是未央; 博客首頁(yè): 未央.303 系列專欄:實(shí)戰(zhàn)項(xiàng)目 每日一句:人的一生,可以有所作為的時(shí)機(jī)只有一次,那就是現(xiàn)在?。?!! 文章目錄 前言 項(xiàng)目介紹 一、MVC模式簡(jiǎn)介 1.1??MVC 模式含義 1.2?MVC 的工作流程 二、項(xiàng)目概述 2.1?項(xiàng)目的幾個(gè)頁(yè)面 2.2?功能大概

    2024年02月07日
    瀏覽(25)
  • 大型醫(yī)院云HIS系統(tǒng):采用前后端分離架構(gòu),前端由Angular語(yǔ)言、JavaScript開發(fā);后端使用Java語(yǔ)言開發(fā) 融合B/S版電子病歷系統(tǒng)

    大型醫(yī)院云HIS系統(tǒng):采用前后端分離架構(gòu),前端由Angular語(yǔ)言、JavaScript開發(fā);后端使用Java語(yǔ)言開發(fā) 融合B/S版電子病歷系統(tǒng)

    一套醫(yī)院云his系統(tǒng)源碼 采用前后端分離架構(gòu),前端由Angular語(yǔ)言、JavaScript開發(fā);后端使用Java語(yǔ)言開發(fā)。融合B/S版電子病歷系統(tǒng),支持電子病歷四級(jí),HIS與電子病歷系統(tǒng)均擁有自主知識(shí)產(chǎn)權(quán)。 文末卡片獲取聯(lián)系! 基于云計(jì)算技術(shù)的B/S架構(gòu)的醫(yī)院管理系統(tǒng)(簡(jiǎn)稱云HIS),采用前后

    2024年02月03日
    瀏覽(31)
  • 前后端分離------后端創(chuàng)建筆記(02)

    前后端分離------后端創(chuàng)建筆記(02)

    ?本文章轉(zhuǎn)載于【SpringBoot+Vue】全網(wǎng)最簡(jiǎn)單但實(shí)用的前后端分離項(xiàng)目實(shí)戰(zhàn)筆記 - 前端_大菜007的博客-CSDN博客 僅用于學(xué)習(xí)和討論,如有侵權(quán)請(qǐng)聯(lián)系 源碼:https://gitee.com/green_vegetables/x-admin-project.git 素材:https://pan.baidu.com/s/1ZZ8c-kRPUxY6FWzsoOOjtA 提取碼:up4c 項(xiàng)目概述筆記:https://blog

    2024年02月12日
    瀏覽(20)
  • 前后端分離------后端創(chuàng)建筆記(07)表單驗(yàn)證

    前后端分離------后端創(chuàng)建筆記(07)表單驗(yàn)證

    4.1 定義一個(gè)方法 ?4.2 這里表單的數(shù)據(jù)在哪里,就是這個(gè) 4.3? this.userForm,這里能夠讓數(shù)據(jù)清空 6.1 有兩種常規(guī)的驗(yàn)證,第一種是非空驗(yàn)證,另一種長(zhǎng)度驗(yàn)證,這一種非常普遍,因此在ELEMTUI中做了一些封裝,因此我們直接拿過來(lái)用就行,還有一種情況,像電子郵件,這種情況就

    2024年02月13日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包