基于Springboot+Mybatis+Thymeleaf用户管理模块实战教程-v2025.01

目录

一、引言

二、技术栈简介

2.1 Spring Boot 快速入门

2.2 Mybatis 核心概念

2.3 Thymeleaf模板引擎基础

三、环境搭建准备

3.1 开发工具与 JDK 版本选择

3.2 项目依赖引入

四、数据库设计与连接

4.1 用户表设计

4.2 Spring Boot 连接数据库配置

五、代码实现:分层架构搭建

5.1实体类(Entity)创建

5.2 Mapper 接口与 XML 映射文件

5.3 Service 层业务逻辑编写

5.4 Controller 层接口定义

六、Thymeleaf 页面渲染

6.1 页面模板创建

6.2 数据绑定与展示

七、功能测试与调试

7.1 功能测试

7.2 调试技巧分享

八、总结与拓展


一、引言

在当今的软件开发领域,高效、灵活地构建应用程序是每个开发者追求的目标。Spring Boot、MyBatis 和 Thymeleaf 作为 Java 开发中的热门技术组合,为开发者提供了强大的支持,能够显著提升开发效率与应用性能。

Spring Boot 以其自动配置、起步依赖等特性,极大地简化了项目的初始搭建与配置过程,让开发者可以专注于业务逻辑的实现,无需在繁琐的配置细节上耗费过多精力。MyBatis 作为一款优秀的持久层框架,提供了灵活的 SQL 操作与映射功能,既能满足复杂的数据库交互需求,又能通过缓存机制提升数据访问性能,确保数据持久化的高效与可靠。而 Thymeleaf 作为模板引擎,支持在 HTML 中直接嵌入动态数据,实现了前端页面的动静分离,既方便前端开发人员直接在浏览器中查看样式,又能让后端开发人员根据真实数据查看显示效果,促进了团队协作。

对于广大开发者来说,掌握这一技术组合至关重要。通过学习基于 Spring Boot + MyBatis + Thymeleaf 的用户管理模块开发,不仅可以深入理解这些技术的协同工作原理,更能将所学应用于实际项目,应对各种复杂的业务场景,提升自身的竞争力。接下来,就让我们一同深入探索这一精彩的技术世界。

二、技术栈简介

2.1 Spring Boot 快速入门

Spring Boot是一个基于 Spring 框架的快速开发框架,它的设计初衷是为了简化 Spring 应用的初始搭建以及开发过程。其最具魅力的特性之一便是自动配置,这意味着开发者在引入相关依赖后,Spring Boot 能够依据类路径中的依赖、环境变量等信息,自动完成大量繁杂的配置工作,使得开发者无需再逐个配置数据源、日志框架、Web 容器等组件,真正实现了“开箱即用”。例如,当我们在项目中引入了Spring Boot的Web Starter依赖,它会自动为我们配置好内嵌的Tomcat服务器,默认的端口号为8080,若想更改端口,只需在配置文件中简单设置server.port=8896即可。

起步依赖也是Spring Boot的一大亮点,它将常用的功能模块进行了整合,以starter的形式提供给开发者。比如,若要开发一个 Web 应用,只需引入spring-boot-starter-web依赖,它便会自动帮我们引入 Spring MVC、Jackson(用于 JSON 处理)等相关依赖,避免了开发者手动去管理这些复杂的依赖关系,极大地提高了开发效率。

下面通过一个简单的示例来感受Spring Boot的便捷性。首先,使用 IDEA 创建一个新的 Spring Boot 项目,在项目创建向导中,选择合适的 Spring Boot 版本(本教程以 2.1.7.RELEASE 为例),并勾选所需的依赖,如 Web、Thymeleaf 等。创建完成后,项目结构清晰明了,默认的目录布局遵循了约定俗成的规范,src/main/java用于存放 Java 源文件,src/main/resources用于存放配置文件、静态资源等。在src/main/java下的主启动类上,标注@SpringBootApplication注解,这是一个复合注解,它包含了@Configuration(表明该类是一个配置类)、@EnableAutoConfiguration(开启自动配置)和@ComponentScan(组件扫描,用于发现 Spring 组件)。编写一个简单的 Controller 类:

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class HelloController {

    @GetMapping("/hello")

    public String hello() {

        return "Hello, Spring Boot!";

    }

}

直接运行主启动类的main方法,无需额外配置 Web 服务器,便可在浏览器中访问http://localhost:8080/hello,看到页面输出 “Hello, Spring Boot!”,如此简单几步,一个基础的 Web 服务便搭建完成,充分展现了 Spring Boot 的高效便捷。

注意:

  • @Controller:这是 Spring 框架中用于定义控制器类的注解。在传统的 Spring MVC 应用中,@Controller注解标记的类主要用于处理 HTTP 请求,并且返回一个视图名称(通常是一个 HTML 页面的名称)。它和视图解析器(View Resolver)一起工作,将请求处理后的数据传递给视图,由视图来进行最终的页面渲染。
  • @RestController:这是 Spring 4.0 之后引入的一个组合注解,它是@Controller@ResponseBody注解的组合。@RestController注解标记的类中的方法默认会将返回对象直接序列化为 JSON(或者其他合适的消息格式)返回给客户端,而不是返回一个视图名称。主要用于构建 RESTful Web 服务,重点在于数据的传输而不是视图的渲染。

2.2 Mybatis 核心概念

MyBatis作为一款出色的持久层框架,致力于解决Java对象与SQL语句之间的映射问题,让开发者能够更加灵活、高效地操作数据库。其工作原理围绕着几个核心概念展开。

首先是SQL映射,MyBatis允许开发者将 SQL语句写在XML映射文件中,或者使用注解直接标注在 Mapper接口方法上。例如,对于一个简单的查询用户信息的功能,在XML映射文件中可以这样定义:

<mapper namespace="com.example.dao.UserDao">

    <select id="getUserById" resultType="com.example.entity.User">

        SELECT * FROM user WHERE id = #{id}

    </select>

</mapper>

这里的namespace指定了对应的 Mapper 接口全限定名,id与 Mapper 接口中的方法名相对应,resultType则明确了查询结果要映射成的Java对象类型。通过这种方式,将SQL语句与业务逻辑代码分离,使得代码结构更加清晰,易于维护。

参数传递在MyBatis中也十分灵活,支持多种数据类型作为参数。对于基本数据类型和包装类,直接在 SQL 语句中使用#{}占位符即可,MyBatis 会自动进行参数设置。例如:

public interface UserDao {

    User getUserById(int id);

}

对应的XML映射:

<select id="getUserById" resultType="com.example.entity.User">

    SELECT * FROM user WHERE id = #{id}

</select>

当传入参数为对象时,#{}中的值对应对象的属性名,MyBatis 会通过反射获取属性值进行参数设置。比如查询符合特定条件的用户列表:

public interface UserDao {

    List<User> getUsersByCondition(User user);

}

XML 映射:

<select id="getUsersByCondition" resultType="com.example.entity.User">

    SELECT * FROM user

    <where>

        <if test="username!= null">

            AND username LIKE '%${username}%'

        </if>

        <if test="age!= null">

            AND age = #{age}

        </if>

    </where>

</select>

这样可以根据传入的User对象的属性值动态生成查询条件,满足复杂的查询需求。

结果集处理方面,MyBatis能够依据resultTyperesultMap将查询结果精准映射到Java对象。resultType适用于简单的字段与属性一一对应的情况,而resultMap则更为强大,可处理复杂的映射关系,如关联查询结果的映射。例如,当查询用户及其关联的订单信息时,通过自定义resultMap

<resultMap id="UserWithOrdersResultMap" type="com.example.entity.User">

    <id property="id" column="user_id"/>

    <result property="username" column="username"/>

    <collection property="orders" ofType="com.example.entity.Order">

        <id property="id" column="order_id"/>

        <result property="orderNo" column="order_no"/>

        <result property="amount" column="amount"/>

    </collection>

</resultMap>

<select id="getUserWithOrders" resultMap="UserWithOrdersResultMap">

    SELECT u.id as user_id, u.username, o.id as order_id, o.order_no, o.amount

    FROM user u

    LEFT JOIN orders o ON u.id = o.user_id

    WHERE u.id = #{id}

</select>

如此,便能将查询出的用户与订单信息完美映射到对应的Java对象中,方便后续业务逻辑处理,充分展现了 MyBatis 在持久层操作的高效性与灵活性。

2.3 Thymeleaf模板引擎基础

Thymeleaf是一款现代服务器端Java模板引擎,它的出现为Web开发带来了全新的体验,尤其是在实现前后端分离方面表现卓越。与传统的JSP等模板引擎不同,Thymeleaf 支持在HTML文件中直接嵌入动态数据,使得前端页面既能在浏览器中直接以静态原型的方式展示样式,又能在服务器端渲染时动态替换数据,极大地促进了前端开发人员与后端开发人员的协作。

其核心语法丰富且易用。在 HTML 文件中,首先需要引入 Thymeleaf 的命名空间:xmlns:th="http://www.thymeleaf.org",之后便可以使用 Thymeleaf 的各种属性。例如,使用th:text属性来输出动态文本:

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

    <meta charset="UTF-8">

    <title>Thymeleaf示例</title>

</head>

<body>

    <p th:text="${message}">这是一段默认文本,将被替换</p>

</body>

</html>

在后端,将数据传递给视图时,比如在Spring Boot的Controller中:

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.GetMapping;

@Controller

public class ThymeleafController {

    @GetMapping("/")

    public String index(Model model) {

        model.addAttribute("message", "欢迎使用Thymeleaf");

        return "index";

    }

}

当访问根路径时,Thymeleaf 会将message的值替换到 HTML 中的相应位置,展示出 “欢迎使用 Thymeleaf!”。

再如,使用th:each属性进行循环遍历,假设后端传递了一个用户列表:

@GetMapping("/users")

public String users(Model model) {

    List<User> userList = userService.getAllUsers();

    model.addAttribute("users", userList);

    return "users";

}

在前端users.html页面中:

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

    <meta charset="UTF-8">

    <title>用户列表</title>

</head>

<body>

    <table>

        <tr>

            <th>姓名</th>

            <th>年龄</th>

        </tr>

        <tr th:each="user : ${users}">

            <td th:text="${user.name}"></td>

            <td th:text="${user.age}"></td>

        </tr>

    </table>

</body>

</html>

这样便能将用户列表中的每个用户信息逐行展示在表格中,通过这些简单而强大的语法,Thymeleaf让页面渲染变得更加灵活、高效,为用户带来出色的交互体验。

三、环境搭建准备

3.1 开发工具与 JDK 版本选择

在开始基于 Spring Boot + MyBatis + Thymeleaf 的用户管理模块开发之旅前,精心挑选合适的开发工具与 JDK 版本至关重要,这将为整个开发过程奠定坚实的基础。

对于开发工具,强烈推荐使用IntelliJ IDEA。它以其智能的代码补全、强大的代码导航、便捷的版本控制系统集成等诸多特性,深受广大Java开发者的喜爱。在使用IDEA创建Spring Boot项目时,其友好的向导界面能够引导开发者快速完成项目的初始搭建,轻松引入所需的依赖,大大提高了开发效率。

JDK版本方面,建议选择Java 8或更高版本。Java 8引入了诸多实用特性,如Lambda表达式、Stream API 等,这些特性在处理集合数据、编写简洁高效的代码时发挥着巨大作用,能够让开发者更加流畅地实现业务逻辑。同时,较高版本的JDK在性能优化、安全性方面也有显著提升,确保项目在运行时稳定可靠,为用户管理模块的开发提供有力保障。

3.2 项目依赖引入

在基于 Maven 构建的项目中,pom.xml 文件承载着管理项目依赖的重任,合理引入相关依赖是项目成功运行的关键。以下是一些关键依赖的详细介绍:

首先是Spring Boot相关依赖,spring-boot-starter-web是开发 Web 应用的核心依赖,它整合了Spring MVC、Tomcat 等组件,使得开发者无需繁琐配置,即可快速搭建起一个Web服务。例如,当我们创建一个简单的Controller类并标注@RestController注解后,无需额外配置,项目启动时便自动具备处理 HTTP 请求的能力。

spring-boot-starter-thymeleaf为引入Thymeleaf模板引擎提供支持,它让后端开发人员能够方便地将动态数据渲染到HTML页面中。在配置文件中,通过设置spring.thymeleaf.prefix指定模板文件的前缀路径,spring.thymeleaf.suffix指定后缀,如.html,这样 Thymeleaf 就能精准定位模板文件进行渲染。

MyBatis 相关依赖不可或缺,mybatis-spring-boot-starter实现了MyBatis与Spring Boot的无缝集成,它自动配置了MyBatis的核心组件,如SqlSessionFactory等。同时,引入mysql-connector-java作为 MySQL 数据库的驱动依赖,确保项目能够与 MySQL 数据库建立连接,进行数据的持久化操作。

以下是电商系统用户管理模块的 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>
    <groupId>com.lifh</groupId>
    <artifactId>shopping</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shopping</name>
    <description>shopping</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <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>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.lifh.shopping.ShoppingApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

在实际开发中,可根据项目需求灵活调整依赖版本及内容,确保项目依赖的准确性与完整性。

四、数据库设计与连接

4.1 用户表设计

在用户管理模块中,合理设计用户表结构是基础且关键的一环。一个结构清晰、字段合理的用户表能够满足多样化的业务需求,确保数据的准确性与完整性。

通常情况下,用户表包含以下核心字段:

  1. 用户账号(uaccount:这是用户在系统中的标识和主键,一般采用INT类型,长度根据实际需求设定,常见的如int(11),确保能容纳相应数量的用户,且需设置唯一性约束,以保证每个用户名在系统中独一无二,避免混淆。
  2. 密码(upassword:用于用户身份验证,同样为字符串类型,考虑到安全性与密码的复杂性,长度可设为 VARCHAR (100) 左右,存储时建议采用加密算法对密码进行加密处理,如常见的 MD5、SHA-256 等加密方式,防止密码明文存储带来的安全隐患。
  3. 用户名(uname:用于表示用户名称,数据类型为 VARCHAR,长度适中,如 VARCHAR (100)。
  4. 用户性别(usex:可以使用VARCHAR类型表示,如 VARCHAR(10)。
  5. 注册时间(register_time:记录用户加入系统的时间节点,一般采用 datetime 类型,精准到具体的年、月、日、时、分、秒,该字段能为后续的数据分析提供时间维度的参考,如统计不同时间段的用户增长趋势。

例如,以下是创建用户表的 SQL 示例:

CREATE TABLE `user`  (

  `uaccount` int(11) NOT NULL AUTO_INCREMENT COMMENT '账号',

  `upassword` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

  `uname` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

  `usex` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

  `register_time` datetime NULL DEFAULT NULL,

  PRIMARY KEY (`uaccount`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 10034 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

通过精心设计这些字段,并合理设置字段类型与约束,能够为后续的用户管理操作提供坚实的数据基础,确保系统稳定、高效运行。

4.2 Spring Boot 连接数据库配置

在 Spring Boot 项目中,实现与数据库的顺畅连接是至关重要的一步,这需要在application.propertiesapplication.yml配置文件中进行精准配置。

对于application.properties文件,以连接MySQL数据库为例,配置如下:

spring.datasource.url=jdbc:mysql://localhost:3306/shopping?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8

spring.datasource.username=root

spring.datasource.password=Hua_2020

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

这里,spring.datasource.url指定了数据库的连接地址,其中localhost表示本地数据库,3306是 MySQL 的默认端口,shopping是数据库名称,serverTimezone=GMT%2B8用于设置时区,避免因时区问题导致的数据存储与查询异常;spring.datasource.usernamespring.datasource.password分别为数据库的用户名和密码,需根据实际数据库设置填写;spring.datasource.driver-class-name明确了数据库驱动类名,对于 MySQL 8 及以上版本,通常使用com.mysql.cj.jdbc.Driver

若使用application.yml文件,配置则更为简洁直观:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/shopping?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
    username: root
    password: Hua_2020
    driver-class-name: com.mysql.cj.jdbc.Driver

这种层级式的配置结构,清晰地展示了数据源的各项配置信息,方便阅读与维护。

完成上述配置后,Spring Boot 在启动时便能自动加载这些配置,创建与数据库的连接池,实现项目与数据库的无缝通信,为后续的数据操作提供有力支持。

五、代码实现:分层架构搭建

5.1实体类(Entity)创建

在用户管理模块中,实体类是对现实世界中用户概念的抽象映射,它直接与数据库表结构相对应,承载着数据的传输与存储功能。以用户实体为例,使用 Java 语言创建一个名为User的实体类,代码如下:

import java.util.Date;

public class User {
    private String uaccount,upassword,uname,usex;
    private Date registerTime;

    public String getUaccount() {
        return uaccount;
    }

    public void setUaccount(String uaccount) {
        this.uaccount = uaccount;
    }

    public String getUpassword() {
        return upassword;
    }

    public void setUpassword(String upassword) {
        this.upassword = upassword;
    }

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUsex() {
        return usex;
    }

    public void setUsex(String usex) {
        this.usex = usex;
    }

    public Date getRegisterTime() {
        return registerTime;
    }

    public void setRegisterTime(Date registerTime) {
        this.registerTime = registerTime;
    }
}

在上述代码中,通过IDEA工具的代码提示功能自动生成了常用的gettersettertoString等方法,简化了代码编写。每个属性都与数据库表中的字段紧密对应,uaccount通常作为主键,用于唯一标识每个用户;upasswordunameusex分别存储用户的密码、登录名与性别信息;registerTime记录用户注册的具体时间,精确到时分秒,为后续的数据分析与用户行为追踪提供有力支持。这样的实体类设计,确保了数据在不同层之间传递的准确性与一致性,为整个系统的稳定运行奠定了基础。

5.2 Mapper 接口与 XML 映射文件

Mapper 接口作为连接 Java 代码与数据库操作的桥梁,定义了一系列操作数据库的方法,而与之对应的 XML 映射文件则负责将这些方法映射为具体的 SQL 语句,实现数据的精准持久化。

首先创建UserDao接口,代码如下:

import com.lifh.shopping.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface UserDao {
     User login(@Param(value = "uname") String uname);//
用户登录接口
   
int register(@Param(value = "upassword")String upassword, @Param(value = "uname")String uname, @Param(value = "usex") String usex, @Param(value = "registerTime") String registerTime);//用户注册接口
}

在这个接口中,@Mapper注解表明这是一个MyBatis的Mapper接口,Spring Boot启动时会自动扫描并加载。每个方法都有明确的功能,如login根据用户uname使用用户登录接口,register用于注册插入新用户数据,方法参数通过@Param注解指定,确保参数在SQL语句中正确绑定。

对应的 XML 映射文件UserMapper.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lifh.shopping.dao.UserDao">

    <insert id="register" parameterType="java.lang.String">
        INSERT INTO USER(upassword,uname,usex,register_time) VALUES
        (#{upassword},#{uname},#{usex},#{registerTime})
    </insert>
    <select id="login" resultType="com.lifh.shopping.model.User"
            parameterType="java.lang.String">
        select * from user where uname=#{uname}
    </select>

</mapper>

在 XML 文件中,namespace必须与 Mapper 接口的全限定名一致,确保 MyBatis 能够正确关联。每个<select><insert><update><delete>标签分别对应 Mapper 接口中的查询、插入、更新、删除方法,id属性与接口方法名相同,resultType指定查询结果映射的 Java 对象类型。对于插入操作,keyPropertyuseGeneratedKeys设置用于获取自增主键的值并回填到实体对象中,确保数据完整性。通过这样的设计,MyBatis 能够高效地执行数据库操作,满足用户管理模块的各种数据需求。

5.3 Service 层业务逻辑编写

Service 层处于业务逻辑处理的核心位置,它负责协调 Mapper 层与 Controller 层之间的数据交互,封装复杂的业务规则,为上层提供简洁、统一的接口。

首先创建UserService接口,定义业务方法:

import com.lifh.shopping.model.User;

public interface UserService {
    public User login(String uname);
    public  int register(String upassword,String uname,String usex);
}

这些方法基于 Mapper 层的基础操作,进一步抽象出更符合业务需求的功能,如register方法将用户注册过程封装,不仅仅是简单的数据插入,还可能包含密码加密、数据合法性校验等操作;updateUser在更新数据时,可能涉及到对更新前后数据的对比、日志记录等业务逻辑。

接着创建UserService接口的实现类UserServiceImpl

import com.lifh.shopping.dao.UserDao;
import com.lifh.shopping.model.User;
import com.lifh.shopping.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDao;
    @Override
    public User login(String uname) {
        return userDao.login(uname);
    }
    @Override
    public int register(String upassword, String uname, String usex) {
        //
新增注册时间采用现在时间进行转换为String格式存入数据库
       
LocalDateTime now = LocalDateTime.now();
        //
创建一个DateTimeFormatter对象,并定义日期格式
       
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //
使用DateTimeFormatterformat方法将LocalDateTime对象转换为字符串
       
String registerTime = now.format(formatter);
        return userDao.register(upassword,uname,usex,registerTime);
    }
}

在实现类中,通过@Autowired注解注入UserDao实例,实现对 Mapper 层方法的调用。register方法对密码进行简单加密后再调用插入方法,体现了业务逻辑的封装。若插入操作影响的行数大于 0,则返回true表示注册成功,其他方法同理,依据 Mapper 层操作结果反馈业务操作的成败,使得上层调用者无需关心底层细节,专注于业务流程的控制。

5.4 Controller 层接口定义

Controller 层作为前后端交互的枢纽,负责接收前端传来的 HTTP 请求,调用 Service 层处理业务逻辑,并将结果返回给前端,实现数据的双向流通。

创建UserController类,示例代码如下:

import com.lifh.shopping.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/admin")
public class UserController {
    @Autowired
    UserService userService;
    //
跳转登录界面
   
@GetMapping(value = "/tologin")
    public String tologin() {
        return "login";
    }
    //
跳转注册界面
   
@GetMapping(value = "/toregister")
    public String toregister() {
        return "register";
    }
    //
用户登录
   
@GetMapping(value = "/login")
    public String login(String uname, String upassword, HttpServletRequest request) {
       // System.out.print("
页面密码:"+upassword);
       // System.out.print("
后端数据库密码:"+userService.login(uname).getUpassword());
       // System.out.print("
后端数据库密码:"+userService.login(uname).getUpassword().toString());
       
if (userService.login(uname) != null) {
            if (userService.login(uname).getUpassword().equals(upassword)){
                HttpSession session = request.getSession(true);
                session.setAttribute("user", userService.login(uname));  //
将登陆者信息存入session
               
System.out.print("登录成功");
                return "redirect:http://localhost:8896/goods/getAll?uaccount="+userService.login(uname).getUaccount()+"&upasswoed="+userService.login(uname).getUpassword();
            }
        }
        // request.setAttribute("mag","
账号密码错误");
       
System.out.print("登录成功");
        return "login";
    }
    //
用户注册
   
@GetMapping(value = "/register")
    public String register(HttpServletRequest request,String upassword,String uname,String usex) {
        if(userService.register(upassword, uname, usex)>0){
            System.out.print("
注册成功");
            return "login";
        }
        System.out.print("
注册失败");
        return "register";
    }
}

在上述代码中,@Controller注解表明这是一个 Spring MVC 的控制器类,@RequestMapping("/admin")为该控制器的基础路径,方便对用户相关接口进行统一管理。@GetMapping@PostMapping@PutMapping@DeleteMapping分别对应 HTTP 的 GET、POST、PUT、DELETE 请求方法,通过@PathVariable获取路径参数,如用户 ID;通过@RequestBody接收前端传来的 JSON 数据并自动转换为User对象。对于查询单个用户和用户列表的操作,将获取的数据添加到Model中,以便 Thymeleaf 模板引擎渲染视图时使用;而对于注册、更新、删除操作,直接返回操作结果的布尔值给前端,前端可依据此结果进行相应提示,实现了前后端的高效交互,满足用户管理模块的各种操作需求。

六、Thymeleaf 页面渲染

6.1 页面模板创建

在 Spring Boot 项目中,Thymeleaf 模板默认存放在resources/templates目录下。在此目录下创建 HTML 文件,如login.html用于展示登陆页面,register.html用于展示注册信息。以register.html为例,首先在文件开头引入 Thymeleaf 的命名空间xmlns:th="http://www.thymeleaf.org"

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:with="title='
宇阳商城登录',active='home'">
<head>
    <meta charset="utf-8" />
    <title>
宇阳商城-注册</title>
    <script type="text/javascript">
        function checkinput()
        {
            if(myform.username.value=="")
            {
                alert("
请输入用户名");
                myform.username.focus();
                return false;
            }
            if (myform.pass_word.value=="")
            {
                alert("
请输入密码");
                myform.pass_word.focus();
                return false;
            }

            if(myform.pass_word.value != myform.pwdconfirm.value){
                alert("
你输入的两次密码不一致,请重新输入!");
                myform.pass_word.focus();
                return false;
            }
            if (myform.userSex.value=="")
            {
                alert("
请输入性别");
                myform.userSex.focus();
                return false;
            }
        }
        function check(){
            var checkbox = document.getElementById("ch");//
选中checkboxid
           
if(checkbox.checked==true){//按钮已选中
                
document.getElementById("but").style.backgroundColor="whitesmoke";
                document.getElementById("but").style.color="#000";
                document.getElementById("but").removeAttribute("disabled");//
移除disabled
           
}else{
                document.getElementById("but").disadled="disabled";
            }
        }
    </script>
    <style type="text/css">

        body{
            color: whitesmoke;

            background-color: rgba(0, 0, 0, 0.06);
            background-image: url(http://localhost:8896/img/13.png);
        }
        .container{
            /*border-radius: 25px;*/
            /*box-shadow: 0 0 20px #222;*/
           
width: 450px;
            height: 500px;
            margin: 0 auto;
            text-align: center;
            margin-top: 200px;
            background: url(http://localhost:8896/img/13.png) no-repeat;
        }
        .right {
            position: relative;
            top:45px;
            text-align: center;
        }
        button{
            background-color: rgba(230, 228, 236, 0.93);
            border: none;
            color: rgba(16, 17, 17, 0.34);
            padding: 10px 70px;
            text-align: center;
            display: inline-block;
            font-size: 16px;
            cursor: pointer;
            margin-top: 30px;
            margin-left: 50px;
        }
    </style>
</head>
<body >
<form action="/admin/register" method="get" name="myform" onsubmit=" return checkinput();" >
    <div class="container" >
        <div class="right" >
            <h1 align="center">
宇阳用户注册</h1>
            <p>
用  户: <input type="text" style="width: 150px" name="uname" id="username" placeholder="请输入姓名"></p>
            <p>
密  码: <input  type="password" style="width: 150px" name="upassword" id="pass_word" placeholder="请输入密码"></p>
            <p>
确认密码: <input   type="password" style="width: 150px" name="pwdconfirm" id="pwdconfirm"  placeholder="请确认密码"></p>
            <p>
性  别: <input  type="text" style="width: 150px" name="usex" id="userSex" placeholder="请输入性别"></p>
            <br/><br/>
            <input type="checkbox" name="agree"  id="ch" onclick="check()"  style="margin-left:5px;display:inline-block;" value="0"/>
            <span style="font-size:20px;text-align: center;">
我已阅读并同意《用户注册协议》</span>
            <p><button type="submit" value="
注册" disabled="disabled" id="but">立即注册</button></p>
        </div>
    </div>
</form>
</body>
</html>

这便设计了一个基本的用户注册页面,该页面编写了2个JavaScript函数checkinput()和check();设置了Html中元素的样式。<form action="/admin/register" method="get" name="myform" onsubmit=" return checkinput();" > 表单通过checkinput函数校验注册信息的是否存在和密码校验,并提交到Controller控制层的/admin/register地址。  <input type="checkbox" name="agree"  id="ch" onclick="check()"  style="margin-left:5px;display:inline-block;" value="0"/>
            <p><button type="submit" value="注册" disabled="disabled" id="but">立即注册</button></p>。通过check()函数控制用户注册协议的是否同意,并激活注册按钮。
login.html用于展示登陆页面的模板

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org
" th:with="title='
宇阳商城登录',active='home'">
<head>
    <meta charset="utf-8" />
    <title>
登录页面</title>
    <link rel="stylesheet" type="text/css" href="http://localhost:8896/css/public.css" />
    <link rel="stylesheet" type="text/css" href="http://localhost:8896/css/login.css"/>
</head>
<body>
<div class="box">
    <div class="dly">
        <div class="dly_left"></div>
        <form action="http://localhost:8896/admin/login" method="get">
            <div class="dly_right">
                <p class="tit">
登陆验证</p>
                <div class="zc_username">
                    <span class="zc_tit">
用户名</span>
                    <input type="text" id="userName" name="uname" class="username" />
                    <!-- for="email"-->
               
</div>
                <div class="zc_password">
                    <span class="zc_tit">
&nbsp;&nbsp;&nbsp;</span>
                    <input type="password" id="password" name="upassword" class="pass_word" />
                    <!-- for="email"-->
                   
<label class="error" id="pass_word_error"></label>
                </div>
                <input id="btn-ty" class="btn-ty" type="submit" value="
登录">
                <p class="cstyle">
没有账号?<a href='http://localhost:8896/admin/toregister'>立即注册</a></p>
            </div>
        </form>
    </div>
</div>
</body>
</html>

登陆模板中通过一个表单进行登陆提交,如果没有账号通过一个链接进入注册页面。

6.2 数据绑定与展示

在 Controller 层,将从 Service 层获取的数据传递给 Thymeleaf 页面进行展示。例如,在UserControllergetAllUsers方法中:

@GetMapping("/list")

public String getAllUsers(Model model) {

    List<User> users = userService.getAllUsers();

    model.addAttribute("users", users);

    return "user-list";

}

这里将获取到的所有用户列表添加到Model对象中,Model对象就像是一个数据载体,将数据从后端传递到前端页面。

user-list.html页面中,使用 Thymeleaf 的th:each属性遍历用户列表并展示:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>
用户列表</title>
</head>
<body>
<h1>
用户列表</h1>
<table>
    <tr>
        <th>ID</th>
        <th>
用户名</th>
        <th>
性别</th>
        <th>
注册时间</th>
    </tr>
    <tr th:each="user : ${users}">
        <td th:text="${user.uaccount}"></td>
        <td th:text="${user.uname}"></td>
        <td th:text="${user.usex}"></td>
        <!--<td th:text="${user.registerTime}"></td>
       
下面使用dates工具进行格式化时间输出格式
        -->
        
<td th:text="${#dates.format(user.registerTime, 'yyyy-MM-dd HH:mm:ss')}"></td>
    </tr>
</table>
</body>
</html>

th:each="user : ${users}"表示遍历Model中名为users的列表,每次迭代将当前用户对象赋值给user变量,然后通过th:text属性将用户的各个属性值展示在对应的表格单元格中,如${user.uaccount }${user.uname}${user.registerTime }分别展示用户的ID、用户名和注册时间。对于时间通过#dates工具对象进行格式化输出。如此,便实现了后端数据与前端页面的动态绑定,页面能够根据数据库中的实际数据实时更新展示内容,为用户提供直观、准确的信息呈现。

七、功能测试与调试

7.1 功能测试

功能测试是保证软件质量的关键环节,它能够帮助在开发阶段尽早地发现问题,确保各个模块的功能正确性。以用户注册和登录功能为例,我们介绍测试的基本流程和步骤:

注意:thymeleaf的模板是不能直接访问的,是需要通过控制层的方法返回到thymeleaf模板。

控制层的类级地址是/admin

@GetMapping("/list")

public String getAllUsers(Model model) {

    List<User> users = userService.getAllUsers();

    model.addAttribute("users", users);

    return "user-list";

}

@GetMapping(value = "/tologin")
public String tologin() {
    return "login";
}
//
跳转注册界面
@GetMapping(value = "/toregister")
public String toregister() {
    return "register";
}

  • 在浏览器中,输入/admin/list地址就可以测试用户列表视图user-list.html

  • 在浏览器中,输入/admin/toregister地址就可以测试用户注册功能register.html

如果直接访问登陆页面

  • 在浏览器中,输入/admin/tologin地址就可以测试用户注册功能login.html

如果想在测试过程中增加一些日志输出,可以在代码中增加System.out.pring(想输出的信息)

7.2 调试技巧分享

在开发过程中,遇到问题时高效的调试技巧能够帮助我们快速定位并解决问题。以使用 IntelliJ IDEA 为例,介绍一些实用的调试方法。

首先是设置断点,在代码的关键位置,如 Controller 层的方法、Service 层的业务逻辑处理方法、Mapper 接口的实现方

法等,点击行号旁边的空白区域,即可设置断点(会出现一个红点标识)。例如,在UserControllerregisterUser方法中设置断点,当发起用户注册请求时,程序执行到该断点处会自动暂停。

断点设置完成后,启动项目的调试模式(可以通过点击 IDEA 工具栏上的调试按钮或者使用快捷键 Shift + F9),然后按照正常流程操作应用,触发设置断点的代码逻辑。当程序暂停在断点处时,IDEA 的调试窗口提供了丰富的信息查看功能。可以查看变量的值,将鼠标悬停在变量名上,会弹出变量当前的值;在调试窗口的 “Variables” 面板中,能看到当前方法内的所有局部变量及其值,方便我们检查数据是否正确传递与处理。还可以通过 “Step Over”(F8 快捷键)单步执行代码,逐行观察代码的执行过程,了解程序的运行逻辑;使用 “Step Into”(F7 快捷键)可以进入方法内部,深入查看方法的具体执行细节,如跟进 Mapper 接口方法对应的 SQL 执行情况。若发现变量值与预期不符,或者代码执行路径错误,便能及时定位问题根源,进行针对性的代码修改,大大提高开发效率。

八、总结与拓展

基于 Spring Boot + MyBatis + Thymeleaf 的用户管理模块开发教程已接近尾声。通过本教程的学习,我们从搭建环境、设计数据库开始,逐步深入到分层架构搭建、页面渲染、功能测试,完整地构建了一个具备注册和登录的用户管理功能的模块。

在这个过程中,Spring Boot为项目提供了便捷的启动与配置方式,让开发流程更加高效;MyBatis 灵活地处理数据库交互,确保数据持久化的精准与高效;Thymeleaf 则实现了前端页面的动态渲染,优化了用户交互体验。三者协同工作,展现出强大的开发效能。

然而,这仅仅是一个起点。对于渴望进一步提升的开发者来说,还有许多拓展方向等待探索。例如,可以深入研究权限管理功能,结合 Spring Security 或 Shiro 等安全框架,实现不同用户角色对不同功能模块的精细访问控制,提升系统的安全性与保密性;在用户体验优化上,利用前端技术如 Vue.js、React 等与 Thymeleaf 结合,打造更加流畅、美观的交互界面。

希望本教程能成为大家学习路上的得力助手,激发大家不断探索、实践的热情,在 Java 开发的广阔天地中取得更多的成果,让我们携手共进,迈向更高的技术巅峰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值