支持增删查改的进阶版Java Web通讯录超详细教程【SpringBoot+JSP+MySQL+Ajax页面不刷新】

本文详细介绍了一个支持增删查改的前后端分离且运行过程中支持数据异步提交页面完全不刷新的Java Web通讯录,内附全部代码,只要严格按照教程一定能够跑通!

本项目基于MVC框架主要展开,MVC即Model-View-Controller(模型-视图-控制器)架构。View层就是用户交互页面,它负责从Controller层获取系统中的各项数据并进行统一展示,对于这些数据的处理方法、调取逻辑等没有直接关联,不需要关心其实现方式,只是对其加以呈现。Controller层则是整个系统的资源和数据控制中心,它会接收来自于View层的用户操作请求,并调取Model层中相关的Service方法完成业务处理并响应给View层,而Service的业务设计则主要依靠Dao层对于数据库的处理进行完成。

本项目的前后端分离主要体现在后端Controller层只专注于对通讯录数据的调用和处理,当需要向前端输出数据时仅输出json格式的数据前后端通信主要依靠ajax通过url进行json数据相应和传递参数。后端不需要考虑前端如何向用户展示数据,前端也不需要考虑后端时如何进行的数据处理。

本项目使用的具体技术栈包括:Java 17、SpringBoot、JSP、Maven、MySQL8.0.31、MyBatis、jQuery、Bootstrap、Ajax、模态框;前后端通信格式为json格式;软硬件环境及IDE为MacBook Air M2+macOS Ventura 13.1+IntelliJ IDEA 2022+Navicat Premium 16.0.7+Safari 16.5.2。

话不多说,上教程和代码!代码中含有大量注释,记录了大部分在运行时遇到的坑。

一、准备工作

1.配置Tomcat服务器

见链接🔗:Mac OS配置Tomcat服务器教程

2.配置Maven环境

见链接🔗:Mac OS配置Maven环境教程(IntelliJ IDEA)

3.安装MySQL服务器并连接数据库GUI管理工具

首先配置MySQL数据库,教程见链接🔗:Mac OS安装配置MySQL 8.0.31教程,然后连接一个数据库GUI管理工具,笔者使用的是Navicat Premium 16.0.7,也可以使用如Sequel Ace、DBeaver等平替,当然也可以使用MySQL命令行直接操作。以下默认安装了Navicat。

打开Navicat,点击左上角连接,然后选择MySQL请添加图片描述
自定义一个连接名,输入MySQL密码。
请添加图片描述
然后点击左下角的“测试连接”,提示连接成功,点击“好”并点击“保存”。请添加图片描述至此,Navicat Premium成功连接本地MySQL。
请添加图片描述

二、数据库准备

本项目以最简单的通讯录进行,通讯录内包括【姓名】和【联系方式】两部分,除此之外还需要一个数据库内部ID用于精准定位和方便增减数据。
在本地MySQL数据库下新建一个数据库命名为address_book,右击Local MySQL,点击“新建数据库”,在数据库名处输入“address_book”,然后点击“好”。
请添加图片描述
请添加图片描述
双击数据库address_book将其打开,然后在该数据库下右击“表”点击新建表(或command+N快捷新建),新建一个数据表(table),在表中新建三个字段,分别为ID、Name和Phone_number字段类型、长度、null和主键设置如下图,注意ID要勾选自动递增,小窗左上角点击保存,并命名为address_book_data,点击“保存”。
在这里插入图片描述
在这里插入图片描述
如下图所示,在address_book数据库下能够找到address_book_data数据表即可,项目的所有通讯录数据将存储于该table中,此时数据库准备完成。
请添加图片描述

三、项目开发

1.新建SpringBoot工程

打开IDEA,新建Project。
请添加图片描述
左侧选择Spring Initalizr,给自己的项目命名,Type选择Maven,JDK选择17(其他版本的Java JDK也可以),Packaging选择War,然后Next
请添加图片描述
选择Dependencies,分别为Web中的Spring Web和SQL中的MySQL DriverMyBatis Framework,然后Create
请添加图片描述
新建Project完成后,项目结构如图(忽略里面的Demox,笔者实际使用的项目名称为Demo3)。
在这里插入图片描述

2.工程结构

需要新建的主要为两部分

a.后端

com.example.demo3目录下新建四个新Package目录
bean目录下新建Java Class为User
controller目录下新建Java Class为UserController
mapper目录下新建InterfaceUserMapper
service目录下新建Java Class为UserService

b.前端

main目录下,与java和resources平级新建Package为webapp,然后在webapp下新建Directory为WEB-INF,然后在WEB-INF下新建jsp文件index.jsp。由于本项目实现了所有数据全部通过Ajax异步刷新,所以Web页面不需要刷新,只需要一个jsp文件。

完成后,项目最终结构如下:
在这里插入图片描述

3.代码

Talk is cheap!

a.后端代码

User.java
package com.example.demo3.bean;

// model层的实体类,数据访问层
public class User {
    private int ID;
    private String Name;
    private String Phone_number;

    public int getID(){
        return ID;
    }
    public void setID(int ID){
        this.ID = ID;
    }

    public String getName() {
        return Name;
    }
    public void setName(String Name) {
        this.Name = Name;
    }

    public String getPhone_number() {
        return Phone_number;
    }
    public void setPhone_number(String Phone_number) {
        this.Phone_number = Phone_number;
    }
}
UserController.java
package com.example.demo3.controller;

import com.example.demo3.bean.User;
import com.example.demo3.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

// @RestController和@Controller都是Spring框架中用来标识一个类为控制器的注解。
// @RestController注解是Spring4.0版本引入的新特性,它的作用是将该类下的所有方法的返回值都默认为JSON格式的数据。这意味着在使用@RestController
// 注解标注的类中所有方法的返回值都会被自动转换为JSON格式并返回给客户端。而@Controller注解则是Spring MVC框架中的一个基本注解,它的作用是标识一个
// 类为控制器并且该类中的方法通常用来处理HTTP请求和响应。在使用@Controller注解的类中,通常需要配合使用其他注解来实现请求参数绑定、视图渲染等功能
// 比如@RequestMapping、@RequestParam、@ModelAttribute等。
// @RestController是@Controller和@ResponseBody的组合注解

@Controller
// @Controller是一个特殊的@Component,用于标识一个类为控制器层的组件,通常用于接收请求,处理请求参数,调用Service层提供的服务,返回响应结果。
// 控制器Controller层
public class UserController {
    @Autowired
    private UserService userService;

    // @RequestMapping是一个通用的注解,可以用于处理任何类型的HTTP请求,包括GET、POST、PUT、DELETE等。它可以用于类级别和方法级别,用于指定请求的URL路径和请求方法。
    // @GetMapping是@RequestMapping的一个特殊化版本,用于处理HTTP GET请求。它只能用于方法级别,用于指定请求的URL路径。相比于@RequestMapping,它更加简洁明了,也更加易于使用。
    // 总的来说,如果只需要处理HTTP GET请求,建议使用@GetMapping;如果需要处理其他类型的HTTP请求,可以使用@RequestMapping。
    // 注意,这里对于注解的使用会直接影响到view层中ajax对于post和get的选择,对应错了是跑不通的!

    @RequestMapping("/index")
    public String Index(){
        return "index";
    }
    // 指定首页为index.jsp
    @RequestMapping("test")
    @ResponseBody
    // @ResponseBody注解用于将Controller的方法返回的对象,通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据,一般在异步获取数据时使用
    public List<User> getUserList(){
        return userService.getUserList();
    }// 上面这个方法简单将数据库中的所有数据全部输出,在项目中没有实际使用,主要用来帮助理解和debug

    // 用于查找
    @RequestMapping("select")
    @ResponseBody
    public List<User> selectUser(String Name){
        return userService.selectUser(Name);
    }// 返回json格式的结果

    // 用于添加
    @RequestMapping("add")
    @ResponseBody
    public void addUser(String Name,String Phone_number){
        userService.addUser(Name,Phone_number);
    }

    // 用于删除
    @RequestMapping("del")
    @ResponseBody
    public void delUser(int ID){
        userService.delUser(ID);
    }

    // 用于更改
    @RequestMapping("update")
    @ResponseBody
    public void updateUser(int ID,String Name,String Phone_number){
        userService.updateUser(ID,Name,Phone_number);
    }
}
UserMapper.java
package com.example.demo3.mapper;

import com.example.demo3.bean.User;
import org.apache.ibatis.annotations.*;//用于在MyBatis框架中定义Mapper接口
import java.util.List;

@Mapper
// @mapper 是一种数据映射模式,用于将对象与数据库表之间的映射关系定义。它可以帮助程序员简化对数据库的操作,使用对象而不是原始 SQL 语句来操作数据库。
// 帮助开发者能够使用注解或者xml文件通过sql语句直接操作数据库
public interface UserMapper {
    //数据持久层,用于存放sql语句,在SpringBoot中用注解来为每一个方法注入sql语句,也叫Dao层
    @Select("select * from address_book_data")
    List<User> getUserList();
    // 查询数据库中对应的所有数据

    @Select("select * from address_book_data where Name like concat('%',#{Name},'%')")
    List<User> selectUser(String Name);
    //根据Name进行模糊查询

    @Insert("insert into address_book_data(Name,Phone_number)values(#{Name},#{Phone_number})")
    void addUser(String Name,String Phone_number);
    // 向数据库中添加新的数据,主要包括Name和Phone_number,而ID在数据库中作为主键已经设置为自增

    @Delete("delete from address_book_data where ID =#{ID}")
    void delUser(int ID);
    // 根据ID将数据库中的数据删除

    @Update("update address_book_data set Name =#{Name}, Phone_number =#{Phone_number} where ID =#{ID}")
    void updateUser(int ID, String Name, String Phone_number);
    // 更新对应的数据
}
UserService.java
package com.example.demo3.service;

import com.example.demo3.bean.User;
import com.example.demo3.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
// @Component是一个通用的注解,用于标识一个类为Spring容器中的组件,可以被其他组件依赖注入。
// @Service是一个特殊的@Component,用于标识一个类为业务逻辑层的组件,通常用于封装业务逻辑,提供给Controller层调用。
// 业务逻辑层,用于完成功能设计,一般用于调用dao层的接口,实现业务功能
public class UserService {
    @Autowired
    private UserMapper userMapper;

    // 以下五个业务功能分别对应Mapper中的五个数据操作
    public List<User> getUserList(){
        return userMapper.getUserList();
    }
    public List<User> selectUser(String Name){
        return userMapper.selectUser(Name);
    }
    public void addUser(String Name,String Phone_number){
        userMapper.addUser(Name,Phone_number);
    }
    public void delUser(int ID){
        userMapper.delUser(ID);
    }
    public void updateUser(int ID,String Name,String Phone_number){
        userMapper.updateUser(ID,Name,Phone_number);
    }
}

b.前端代码

index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>通讯录</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <%--使用jquery和bootstrap框架,需要添加下面的依赖包--%>
    <script src="webjars/jquery/3.4.1/jquery.min.js"></script>
    <script src="webjars/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="webjars/bootstrap/3.3.5/css/bootstrap.min.css" />

    <style type="text/css">
        h1 {
            text-align: center;
        }

        body {
            background-color: antiquewhite;
        }

        th, td {
            width: 70px;
            height: 35px;
            text-align: center;
        }

        #before {
            text-align: center;
        }
    </style>

    <%--主要用于显示查找到的数据--%>
    <script type="text/javascript">
        function selList(Name){
            $.ajax({
                url:"http://localhost:8080/select?Name="+Name,
                // 通过url进行传参
                type:"post",
                dataType:"json",
                success:function (data){
                    var i;
                    var Userlist = "<thead><tr bgcolor=\"#5f9ea0\"><th>姓名</th><th>电话</th><th>选项</th></tr></thead>";
                    // 把获取到的从后端传来的json格式的数据用for循环拆解
                    for(i = 0; i < data.length; i++){
                        Userlist += "<tbody><tr><td>" + data[i].name + "</td><td>" + data[i].phone_number + "</td><td>"+
                            "<div class=\"btn-group\"><button type=\"button\" class=\"btn btn-info btn-sm\" οnclick=editUser('"+
                            data[i].id + "','" + data[i].name + "','" + data[i].phone_number+ "')>编辑</button>"+
                            "<button type=\"button\" class=\"btn btn-danger btn-sm\" οnclick=\"delUser("+
                            data[i].id + ")\">删除</button></div></td></tr></tbody>"
                    }//在查询数据显示的同时,也在对应的数据后方添加了修改和删除的按钮
                    //$("#Listtab").append(Userlist)
                    //上面这行给Userlist设置table标签id为"Listtab"的代码不能使用,会造成ajax刷新时无法清空上一次查询的数据,造成数据无限堆叠非常离谱
                    document.getElementById("Listtab").innerHTML = Userlist;
                },
                error: function(msg){
                    alert("数据查询异常:"+msg);
                }
            });
        }
    </script>

    <%--该函数在上面的编辑按钮处使用,用户在按下编辑按钮后--%>
    <script type="text/javascript">
        function editUser(ID,Name,Phone_number) {
            $("#editModal").modal('show');// 显示模态框
            $("#editName").val(Name);// 在模态框中显示对应数据的Name元素
            $("#editPhone_number").val(Phone_number);// 在模态框中显示对应数据的Phone_number元素
            $("#editbutton").attr("value",ID);// 将editbutton的value属性设为ID,方便在修改数据时能够对应数据的主键ID
        }
    </script>

    <%--该函数用于修改数据--%>
    <script type="text/javascript">
        function updateUser(ID){
            var Name = document.getElementById("editName");
            var Phone_number = document.getElementById("editPhone_number");
            $.ajax({
                url: "http://localhost:8080/update?ID="+ID+"&Name="+Name.value+"&Phone_number="+Phone_number.value,
                type: "post",
                //dataType: "json",
                // 后端在修改完成后没有实际传回参数
                success: function (){
                    alert("数据已修改");
                    $('#editModal').modal('hide')
                    selList("");
                },
                error:function(msg){
                    alert("修改失败:"+msg);
                }
            });
            // 仅更新数据的function,Controller不会给前端返回任何数据,但是对于接受Ajax请求的Controller方法,不管是否需要返回数据
            // 都需要在返回值前面加上@ResponseBody注解,或者说通过Response手动回写一段数据,例如:“OK”,否则ajax的回调函数将无法执行
        }
    </script>

    <%--该函数用于删除数据--%>
    <script type="text/javascript">
        function delUser(ID) {
            $.ajax({
                url: "http://localhost:8080/del?ID="+ID,
                type: "post",
                success: function (){
                    alert("联系人已删除");
                    selList("");
                },
                error:function (msg){
                    alert("删除失败:"+msg);
                }
            });
        }
    </script>

    <%--该函数用于添加数据--%>
    <script type="text/javascript">
        function addUser() {
            var Name = document.getElementById("Name");
            var Phone_number = document.getElementById("Phone_number");
            $.ajax({
                url: "http://localhost:8080/add?Name="+Name.value+"&Phone_number="+Phone_number.value,
                type: "post",
                success: function (){
                    alert("数据已提交");
                    $('#addModal').modal('hide')
                    selList("");
                },
                error:function (msg){
                    alert("添加失败:"+msg);
                }
            });
        }
    </script>
</head>

<body>
<%--大标题--%>
<h1><b>通讯录</b></h1>
<hr/>
<%--用于数据查找的文本输入框--%>
<div id="before">
    <p><input type="text" id="txt1" placeholder="输入姓名进行查找" onkeyup="selList(this.value)"></p>
</div>
<%--在第一次打开的初始页面即以空参数对数据库进行一次查询,起到显示全部数据的效果--%>
<table class="table" align="center" id="Listtab" cellspacing="5">
    <script type="text/javascript">
        selList("");
    </script>
</table>
<%--按钮:添加数据,打开id为addModal的模态框--%>
<div style="text-align:center">
<button class="btn btn-default" data-toggle="modal" data-target="#addModal">添加数据</button>
</div>
<%--模态框(addModal)--%>
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
                &times;
            </button>
            <h4 class="modal-title" id="myModalLabel">
                添加新的数据至通讯录
            </h4>
        </div>
        <div class="modal-body">
            <div>
                <tr>
                    <label>姓名:</label></td>
                    <input type="text" name="Name" id="Name" placeholder="姓名">
                </tr>
            </div>
            <div>
                <tr>
                    <label>电话:</label>
                    <input type="text" name="Phone_number" id="Phone_number" placeholder="电话">
                </tr>
            </div>

        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-primary" onclick="addUser()">添加</button>
            <%--在添加按钮处运行addUser()函数--%>
            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
        </div>
    </div>
</div>
</div>

<%--模态框(editModal)--%>
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
                &times;
            </button>
            <h4 class="modal-title" id="editModalLabel">
                更新通讯录
            </h4>
        </div>
        <div class="modal-body">
            <div>
                <tr>
                    <label>姓名:</label></td>
                    <input type="text" name="Name" id="editName" placeholder="姓名">
                </tr>
            </div>
            <div>
                <tr>
                    <label>电话:</label>
                    <input type="text" name="Phone_number" id="editPhone_number" placeholder="电话">
                </tr>
            </div>

        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-primary" id="editbutton" onclick="updateUser(value)">修改</button>
            <%--在修改按钮处运行updateUser()函数--%>
            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
        </div>
    </div>
</div>
</div>
</body>

</html>

c.配置文件

application.properties
# 数据库连接,注意此处的url和password需要修改成你自己对应的地址和MySQL密码
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/address_book?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=00000000

# 指定视图文件的前缀
spring.mvc.view.prefix=/WEB-INF/
# 指定视图的后缀
spring.mvc.view.suffix=.jsp

d.项目依赖

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>Demo3</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Demo3</name>
    <description>Demo3</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.2</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.2</version>
            <scope>test</scope>
        </dependency>
        <!--用于编译jsp-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <!--用于导入jquery框架的依赖-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--用于导入bootstrap框架的依赖-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

4.项目启动

很简单的两步,首先在IDE右侧工具栏打开Maven,点击Maven工具左上角的刷新按钮Reload All Maven Projects,将项目所需的依赖全部下载。然后IDE右上角绿色三角形一键运行!
在这里插入图片描述

四、项目运行

启动后,在Safari浏览器地址栏中输入http://localhost:8080,即可打开Web页面。
请添加图片描述
顶部查找框支持不区分大小写的姓名实时模糊查询,如输入“y”后将实时显示Sky与Tonyo的数据。请添加图片描述
删除操作就不多解释了,编辑和添加数据均采用了模态框进行操作,简洁美观易操作。点击“编辑”后,弹出对应模态框,可供用户直接修改。
在这里插入图片描述
在这里插入图片描述
点击“添加数据”按钮同理。
在这里插入图片描述
至此,本项目结束。快打开你的电脑试试吧!看在笔者这么肝的份儿上有用的话留个赞👍🥺🥺🥺。

五、补充

最后提一句,由于前后端的彻底分离,本项目将很方便地在保持后端不变的前提下将前端JSP页面迁移至Vue框架,实现更加轻量化的前端开发。链接🔗在这里:支持增删查改的进阶版Java Web通讯录超详细教程【Vue2+SpringBoot+MySQL+Axios,前后端完全分离,附全部代码】

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值