简易的个人博客————简单的Web项目学习

一、项目目标

这次的项目想要实现一个简易的博客功能,包括用户登录、注册,发表新文章,显示文章详情,以及显示文章列表的功能。

二、所需支持

由于前端所需内容皆以大致打包整合完毕,所以只需负责后端的功能实现。
在开始项目前,首先配置好Maven、Mysql、tomcat等配置。

三、具体实现

前端

使用了jquery框架中的ajax与form表单
form表单:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    <script type="text/javascript" src ="../static/jquery/jquery-1.12.4.js"></script>
    <script type="text/javascript" src="../js/app.js"></script>
</head>
<body>
    <h2>用户登录</h2>
    <form id="login_form" method="post" action="../login" enctype="application/x-www-form-urlencoded">
        <input id = "username" type="text" name="username" placeholder="请输入用户名"><br><br>
        <input id = "password" type="password" name="password" placeholder="请输入密码"><br><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

利用form表单完成了前端的登录页面。
ajax:

$(function () {//页面加载完成之后执行function代码
    //jquery,使用$("#id")通过元素id获取某个页面元素
    $("#login_form").submit(function () {
        //ajax自己发请求
        $.ajax({
            url: "../login",//请求的服务路径
            type: "post",//请求方法
            //contentType:""请求的数据类型 请求头Content_type,默认表单格式
            //dataType:"",//响应的数据类型:不适用默认为表单提交的格式,json需要指定
            data:$("#login_form").serialize(),//请求的数据:序列化表单的数据
            dataType:"json",
            success: function (r) {//响应体json字符串,会解析为方法参数
                if(r.success){
                    //前端页面url直接跳转某个路径
                    window.location.href ="../jsp/articleList.jsp";
                }else{
                    alert("错误码: "+r.code+ "\n错误消息: " +r.message)
                }
            }
        })

        //统一不执行默认表单提交
        return false;
    })
})

使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的信息。

后端

1、数据库
利用Mysql语句完成了后端所需要的数据库建表

drop database if exists servlet_blog;
create database servlet_blog character set utf8mb4;

use servlet_blog;

create table user(
    id int primary key auto_increment,
    username varchar(20) not null unique comment '账号',
    password varchar(20) not null,
    nickname varchar(20),
    sex bit,
    birthday date,
    head varchar(50)
);

create table article(
    id int primary key auto_increment,
    title varchar(20) not null,
    content mediumtext not null,
    create_time timestamp default now(),
    view_count int default 0,
    user_id int,
    foreign key(user_id) references user(id)
);

insert into user(username, password) values ('a', '1');
insert into user(username, password) values ('b', '2');
insert into user(username, password) values ('c', '3');

insert into article(title, content, user_id) value ('快速排序', 'public ...', 1);
insert into article(title, content, user_id) value ('冒泡排序', 'public ...', 1);
insert into article(title, content, user_id) value ('选择排序', 'public ...', 1);
insert into article(title, content, user_id) value ('归并排序', 'public ...', 2);
insert into article(title, content, user_id) value ('插入排序', 'public ...', 2);


-- 主外键关联的表,默认创建的主外键约束是restrict严格模式
-- 比如从表有数据关联到主表某一行数据X,那X不能删
-- 真实的设计上是不删除物理物理,在每一张表上设计一个字段,表示是否有效


select id, username, password, nickname, sex, birthday, head from user where username='a';

select id, title from article where user_id=1;

2、Util类

2.1 JSONUtil
Json是一种数据格式,保存在请求体与响应体内,JSONUtil可以实现Java字符串转换成JSON字符串的过程(序列化)以及反序列化操作。

2.2 DBUtil
DBUtil是一个工具类可以提供数据库JDBC操作。

由于项目中需要抛出各种异常,所以我们建立一个自定义异常类来进行统一异常处理.

3、自定义异常

public class AppException extends RuntimeException {

    //给前端返回的json字符串中,保存错误码
    private String code;

    public AppException(String code, String message) {
//        super(message);
//        this.code = code;
        this(code, message, null);
    }

    public AppException(String code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

    public String getCode() {
        return code;
    }
}

处理完这些后,我们就可以开始着手Servlet服务了

4、Servlet服务

4.1 Servlet父类
我们先写了一个父类Servlet,类似接收http请求的一个入口,后面的其他Servlet服务全部继承于父类,运用了模板模式的设计模式,可以完成统一业务的不同实现。
在父类Servlet中,我们要设置请求体的编码格式和响应体的编码与数据类型,然后进行自定义异常的抛出,最后完成统一的数据封装。

public abstract class AbstractBaseServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求体的编码格式
        req.setCharacterEncoding("UTF-8");
        //设置响应体的编码
        resp.setCharacterEncoding("UTF-8");
        //设置响应体的数据类型(浏览器要采取什么方式执行)
        resp.setContentType("application/json");

        //Session会话管理:除登录和注册接口,其他都需要登录后访问
        //req.getServletPath()获取请求服务路径
        //TODO

        JSONResponse json = new JSONResponse();
        try{
            //调用子类重写的方法
            Object data = process(req, resp);
            //子类的process方法执行完没有抛异常,表示业务执行成功
            json.setSuccess(true);
            json.setData(data);
        }catch(Exception e){
            //异常如何处理?JDBC的异常SQLException,JSON处理的异常,自定义异常返回错误消息
            e.printStackTrace();
            //json.setSuccess(false)不用设置了,因为new的时候就是
            String code = "UNKNOWN";
            String s = "未知的错误";
            if(e instanceof AppException){
                code = ((AppException) e).getCode();
                s = e.getMessage();
            }
            json.setCode(code);
            json.setMessage(s);
        }
        PrintWriter pw = resp.getWriter();
        pw.println(JSONUtil.serialize(json));
        pw.flush();
        pw.close();
    }

    protected abstract Object process(HttpServletRequest req,
                                    HttpServletResponse resp) throws Exception;
}

4.2 用户登录
有了前端的用户登陆页面后,我们首要实现的目标就是使用户可以登陆进去,并且可以识别当密码错误与用户名错误时抛出不同的异常。为了实现这个功能,我们还需要一个登录DAO来链接数据库中的用户信息来作为支持。

@WebServlet("/login")
public class LoginServlet extends AbstractBaseServlet {
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        User user = LoginDAO.query(username);
        if(user == null)
            throw new AppException("LOG002", "用户不存在");
        if(!user.getPassword().equals(password))
            throw new AppException("LOG003", "用户名或密码错误");
        //登录成功,创建session
        HttpSession session = req.getSession();
        session.setAttribute("user", user);
        return null;

    }
}

4.3 发表新文章
完成了登录功能后,继续我们就需要完成发表新文章功能。同样需要一个文章DAO来连接到数据库中的文章信息。

@WebServlet("/articleAdd")
public class ArticleAddServlet extends AbstractBaseServlet {
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        HttpSession session = req.getSession(false);
        User user = (User) session.getAttribute("user");
        //请求数据类型是application/json,需要使用输入流获取
        InputStream is = req.getInputStream();
        Article a = JSONUtil.deserialize(is, Article.class);
        a.setUserId(user.getId());
        int num = ArticleDAO.insert(a);
        return null;
    }
}

4.4 修改文章
当发表文章后觉得不满意,我们肯定还需要进行修改功能。

@WebServlet("/articleUpdate")
public class ArticleUpdateServlet extends AbstractBaseServlet {
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        InputStream is = req.getInputStream();
        Article a = JSONUtil.deserialize(is, Article.class);
        int num = ArticleDAO.update(a);
        return null;
    }
}

4.5 删除文章
如果不需要某个文章,可以执行删除功能

@WebServlet("/articleDelete")
public class ArticleDeleteServlet extends AbstractBaseServlet{
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        String ids = req.getParameter("ids");
        int num = ArticleDAO.delete(ids.split(","));
        return null;
    }
}

4.6 文章列表
为了是操作方便,我们还需要能够展示出文章列表并且可以选中执行。也是为了能够是用户的安全性更强。

@WebServlet("/articleList")
public class ArticleListServlet extends AbstractBaseServlet{
    @Override
    protected Object process(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        //Huoqusession,没有就返回null
        HttpSession session = req.getSession(false);
        if(session == null)
            throw new AppException("ART002","用户没有登陆,不允许访问");
        //获取登陆时创建的Session用户纤细
        User user = (User) session.getAttribute("user");
        if(user == null)
            throw new AppException("ART003","会话异常,请重新登录");
        //用户已登录,并且保存了用户信息
        List<Article> articles = ArticleDAO.queryByUserId(user.getId());
        return articles;
    }
}

5、富文本编辑器
一个项目就这样即将完成了,最后添加一个基于百度的富文本编辑器来实现图片的上传功能,为此我们需要先进行以下五步:

  1. 修改idea中tomcat配置的应用上下文路径,maven中的finalName
  2. 修改webapp/static/ueditor/ueditor.config.js,33行修改(应用上下文路径+服务路径)
  3. 实现后端接口(和第二步的服务路径一致)
  4. 修改config.json配置:上传图片到服务器本地的路径,及访问的主机ip,port,应用上下文路径
  5. idea运行时,需要配置tomcat:将tomcat/webapps路径下的项目都部署
@WebServlet("/ueditor")
public class UEditorServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        URL url = UEditorServlet.class.getClassLoader()
                        .getResource("config.json");
        //URL获取到时,都是编码后的字符串,使用时,需要先解码再使用
        String path = URLDecoder.decode(url.getPath(), "UTF-8");
        //框架提供的富文本编辑器上传功能
        MyActionEnter enter = new MyActionEnter(req, path);
        String exec = enter.exec();//执行
        PrintWriter pw = resp.getWriter();
        pw.println(exec);
        pw.flush();
        pw.close();
    }
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本篇文章是 Spring Boot 实践之十三 9 Spring Boot综合项目实战——个人博客系统管理模块 的续篇,本次将介绍如何实现个人博客系统的拓展模块。 在实际开发中,我们常常需要对系统进行扩展,添加一些新的功能模块。为了不影响原有代码的结构和功能,我们可以将这些新功能模块独立成为一个子模块,然后通过配置文件等方式将其与原有系统进行整合。 本文将以一个个人博客系统为例,介绍如何实现博客的拓展模块,具体包括以下几个方面: 1. 拓展模块的设计和实现 2. 拓展模块的集成和配置 3. 拓展模块的使用示例 ## 1. 拓展模块的设计和实现 在本例中,我们将实现一个博客系统的拓展模块,该模块主要提供以下两个功能: 1. 统计博客文章的阅读量并显示 2. 在博客页面添加底部的版权声明 ### 1.1 统计博客文章的阅读量并显示 首先,我们需要在数据库中添加一个字段来存储博客文章的阅读量。在本例中,我们在 `blog` 表中添加 `read_count` 字段来存储阅读量。 ```sql ALTER TABLE `blog` ADD COLUMN `read_count` INT NOT NULL DEFAULT 0 COMMENT '阅读量' AFTER `update_time`; ``` 接下来,在博客文章页面中添加一个阅读量的显示。我们可以在博客文章详情页面的右侧添加一个阅读量的区域,显示该文章的阅读量。具体的实现方式为: 1. 在博客文章详情页面中添加一个阅读量的区域。 2. 在加载博客文章详情页面时,通过 AJAX 请求统计该文章的阅读量,并更新阅读量区域的显示。 具体的代码实现如下: 在博客文章详情页面中添加一个阅读量的区域: ```html <div class="blog-sidebar-item"> <div class="blog-sidebar-title">阅读量</div> <div class="blog-sidebar-content"> <span id="read-count">0</span> </div> </div> ``` 在加载博客文章详情页面时,通过 AJAX 请求统计该文章的阅读量,并更新阅读量区域的显示。具体的实现方式为: ```javascript $(function () { // 统计阅读量 var blogId = $("#blogId").val(); $.ajax({ url: "/blog/read/" + blogId, type: "POST", success: function (result) { if (result && result.success) { $("#read-count").text(result.data); } else { $("#read-count").text(0); } } }); }); ``` 在服务器端,我们需要实现一个接口来统计博客文章的阅读量,并将其保存到数据库中。具体的实现方式为: ```java @RestController @RequestMapping("/blog") public class BlogController { ... /** * 统计博客文章的阅读量 * * @param blogId 博客文章ID * @return 统计结果 */ @PostMapping("/read/{blogId}") public Result<Integer> readBlog(@PathVariable("blogId") Long blogId) { int readCount = blogService.readBlog(blogId); return Result.success(readCount); } ... } ``` 在 `BlogService` 中实现 `readBlog` 方法: ```java @Service public class BlogServiceImpl implements BlogService { ... /** * 统计博客文章的阅读量 * * @param blogId 博客文章ID * @return 统计结果 */ @Override public int readBlog(Long blogId) { Blog blog = blogMapper.selectByPrimaryKey(blogId); if (blog != null) { int readCount = blog.getReadCount() + 1; blog.setReadCount(readCount); blogMapper.updateByPrimaryKeySelective(blog); return readCount; } return 0; } ... } ``` ### 1.2 在博客页面添加底部的版权声明 接下来,我们将在博客页面底部添加一个版权声明。具体的实现方式为: 1. 在博客页面底部添加一个版权声明的区域。 2. 在加载博客页面时,通过 AJAX 请求获取版权声明的内容,并更新版权声明区域的显示。 具体的代码实现如下: 在博客页面底部添加一个版权声明的区域: ```html <div class="blog-footer"> <div><span id="copyright"> 版权声明:本博客所有文章均为作者原创或转载,未经授权禁止转载。 </span></div> </div> ``` 在加载博客页面时,通过 AJAX 请求获取版权声明的内容,并更新版权声明区域的显示。具体的实现方式为: ```javascript $(function () { // 加载版权声明 $.ajax({ url: "/blog/copyright", type: "GET", success: function (result) { if (result && result.success) { $("#copyright") .html("版权声明:" + result.data); } } }); }); ``` 在服务器端,我们需要实现一个接口来获取版权声明的内容。具体的实现方式为: ```java @RestController @RequestMapping("/blog") public class BlogController { ... /** * 获取版权声明的内容 * * @return 版权声明的内容 */ @GetMapping("/copyright") public Result<String> getCopyright() { String content = "本博客所有文章均为作者原创或转载,未经授权禁止转载。"; return Result.success(content); } ... } ``` ## 2. 拓展模块的集成和配置 在上一篇文章中,我们已经将博客系统的所有模块都整合到了一个工程中,因此我们可以通过添加一个 Maven 模块来实现拓展模块的开发,并将其整合到原有工程中。 具体的步骤如下: 1. 在项目根目录下创建一个新的 Maven 模块,命名为 `blog-ext`,并将其添加到工程中。 2. 在 `blog-ext` 模块中添加 `pom.xml` 文件,并添加依赖关系。 3. 在 `blog-ext` 模块中添加 Spring Boot 的配置文件 `application.yml`,并添加相关配置。 4. 在 `blog-ext` 模块中添加拓展模块的代码和资源文件。 ### 2.1 添加 Maven 模块 在项目根目录下创建一个新的 Maven 模块,命名为 `blog-ext`,并将其添加到工程中。具体的步骤如下: 1. 在项目根目录下创建一个新的 Maven 模块,命名为 `blog-ext`。 ```bash $ cd ~/workspace/springboot-blog $ mvn archetype:generate -DgroupId=com.waylau.spring.boot.blog \ -DartifactId=blog-ext -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false ``` 2. 将 `blog-ext` 模块添加到工程中。 ```xml <modules> <module>blog-api</module> <module>blog-service</module> <module>blog-web</module> <module>blog-ext</module> </modules> ``` ### 2.2 添加依赖关系 在 `blog-ext` 模块中添加 `pom.xml` 文件,并添加依赖关系。具体的依赖关系如下: ```xml <dependencies> <dependency> <groupId>com.waylau.spring.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 添加 Spring Web MVC 的依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 添加 MyBatis 的依赖 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.boot.version}</version> </dependency> </dependencies> ``` ### 2.3 添加配置文件 在 `blog-ext` 模块中添加 Spring Boot 的配置文件 `application.yml`,并添加相关配置。具体的配置如下: ```yaml spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/blog?useSSL=false&useUnicode=true&characterEncoding=utf8 username: root password: root mvc: view: prefix: /templates/ suffix: .html resources: static-locations: classpath:/static/ ``` ### 2.4 添加拓展模块的代码和资源文件 在 `blog-ext` 模块中添加拓展模块的代码和资源文件。具体的步骤如下: 1. 在 `blog-ext` 模块中添加 `com.waylau.spring.boot.blog.ext` 包,并在该包下添加 `BlogExtApplication` 类。 ```java @SpringBootApplication(scanBasePackages = "com.waylau.spring.boot.blog.ext") public class BlogExtApplication { public static void main(String[] args) { SpringApplication.run(BlogExtApplication.class, args); } } ``` 2. 在 `blog-ext` 模块中添加 `resources` 目录,并在该目录下添加 `templates` 和 `static` 目录。 3. 在 `templates` 目录中添加 `read-count.html` 和 `copyright.html`。 ```html <!-- read-count.html --> <div class="blog-sidebar-item"> <div class="blog-sidebar-title">阅读量</div> <div class="blog-sidebar-content"> <span id="read-count">0</span> </div> </div> ``` ```html <!-- copyright.html --> <div class="blog-footer"> <div><span id="copyright"> 版权声明:本博客所有文章均为作者原创或转载,未经授权禁止转载。 </span></div> </div> ``` 4. 在 `static` 目录中添加 `js` 目录,并在该目录下添加 `read-count.js` 和 `copyright.js`。 ```javascript // read-count.js $(function () { // 统计阅读量 var blogId = $("#blogId").val(); $.ajax({ url: "/blog/read/" + blogId, type: "POST", success: function (result) { if (result && result.success) { $("#read-count").text(result.data); } else { $("#read-count").text(0); } } }); }); ``` ```javascript // copyright.js $(function () { // 加载版权声明 $.ajax({ url: "/blog/copyright", type: "GET", success: function (result) { if (result && result.success) { $("#copyright") .html("版权声明:" + result.data); } } }); }); ``` ## 3. 拓展模块的使用示例 在完成了拓展模块的开发和配置之后,我们需要将其与原有系统进行整合。具体的步骤如下: 1. 在原有系统中添加对拓展模块的依赖关系。 在 `blog-web` 模块的 `pom.xml` 文件中添加对 `blog-ext` 模块的依赖关系: ```xml <dependencies> ... <!-- 添加 blog-ext 的依赖 --> <dependency> <groupId>com.waylau.spring.boot.blog</groupId> <artifactId>blog-ext</artifactId> <version>${project.version}</version> </dependency> </dependencies> ``` 2. 在原有系统中添加拓展模块的使用示例。 在博客文章详情页面中添加一个阅读量的区域: ```html <!-- 添加阅读量的区域 --> <div th:replace="blog-ext :: read-count"></div> ``` 在博客页面底部添加一个版权声明的区域: ```html <!-- 添加版权声明的区域 --> <div th:replace="blog-ext :: copyright"></div> ``` 经过以上的步骤,我们就已经成功地将博客系统的拓展模块整合到了原有系统中。 ## 总结 本文介绍了如何实现 Spring Boot 的拓展模块,并将其与原有系统进行整合。在实际开发中,我们可以根据具体的需求来实现不同的拓展模块,并通过配置文件等方式将其整合到原有系统中。这种方式既提高了代码的可维护性,又方便了模块的扩展和升级。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值