用户登陆界面
利于springboot构建项目,加入start_datajpa、web、thymeleaf、mysql_connector_j等maven依赖。
创建实体类(model),服务层(service),控制器(controller),数据访问层(dao)
源码:https://github.com/wuzerui378/login_UI
1.首先定义实体类Admin
@Entity
@Table(name = "users")
public class Admin {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
public Admin() {}
public Admin(String username, String password) {
this.username = username;
this.password = password;
}
当你使用 JPA (Java Persistence API) 进行数据持久化时,@Entity
和 @Table
注解是基本且核心的部分。在 JPA 中,这些注解帮助你定义实体类和它们如何映射到数据库的表。
@Entity
注解标记一个类为一个实体类,即一个将要被 JPA 管理的类,该类的实例可以代表数据库中的数据。使用 @Entity
注解后,JPA 将认为这个类的每个实例对应数据库中的一行数据。实体类通常拥有一些带有 @Column
注解的字段,这些字段映射到表的列。
虽然 @Entity
提供了实体类的基本信息,@Table
注解则用来提供特定于表的信息。最常见的用途是指定实体类映射到数据库中的哪个表。如果不使用 @Table
注解,JPA 默认将实体类的名称作为表名。@Table
注解还可以指定如索引和唯一约束等表级别的属性。
@Id
注解标记一个字段作为实体类的主键(Primary Key)。每个实体类必须有至少一个字段用 @Id
注解标记,确保实体在数据库中的唯一性。主键用于实体对象的持久化存储,如果实体被存储到数据库,主键值必须唯一。
@GeneratedValue
注解用于自动生成主键的值。这个注解常与 @Id
注解结合使用,指定主键的生成策略。@GeneratedValue
提供了几种策略来生成主键的值,通过 strategy
属性来指定:
-
GenerationType.IDENTITY:依赖数据库的
IDENTITY
列来生成主键。这意味着主键的值将由数据库自动增长(比如 MySQL 的 AUTO_INCREMENT)。这种策略不依赖于持久化框架的持久化上下文,直接由数据库生成。 -
GenerationType.SEQUENCE:使用数据库的序列来生成主键。这需要数据库支持序列(如 Oracle、PostgreSQL),并需要指定序列名。
-
GenerationType.AUTO:(默认策略)让持久化提供者(如 Hibernate)根据数据库的能力自动选择最合适的策略。
-
GenerationType.TABLE:使用特定的数据库表来模拟序列生成主键。这种策略不依赖于数据库的特定特性,因此在所有数据库中都可用,但可能在高并发时性能较低。
2.定义jpa接口来操作数据库
@Repository
public interface AdminRepository extends JpaRepository<Admin, Integer> {
Admin findByUsername(String username);
}
Repository 模式简介
Repository 模式是一种设计模式,用于将数据访问逻辑和业务逻辑分离。这种模式使得数据访问机制从业务逻辑中解耦,提高了代码的可维护性和可测试性。在 Spring 框架中,Repository 是一种常见的实现方式,用于集中处理数据访问逻辑。
在 Spring 框架中,特别是使用 Spring Data JPA 的情况下,Repository
是一个接口,通常会继承自 CrudRepository
或 JpaRepository
接口。这些接口提供了一套标准的方法来执行数据库操作,如保存、删除、查询等。
Admin findByUsername(String username);
在 Spring Data JPA 中,Admin findByUsername(String username);
是一个例子,展示了如何使用 Spring Data 的仓库接口创建查询方法,无需编写具体的 SQL 或 JPQL 查询语句。这种方法被称为方法名查询,基于方法名的约定,Spring Data JPA 能够自动解析方法名并生成相应的查询。
方法名解释
在 findByUsername(String username)
中:
findBy
是告诉 Spring Data JPA,这是一个查询操作,并且需要根据后面的参数来进行筛选。Username
是实体中的一个属性名。按照 Java Bean 规范,此处假设你的Admin
实体类中有一个名为username
的字段,或者至少有一个获取此字段的方法(getUsername()
)。
这个方法会自动生成一个查询,等价于以下 JPQL 查询:
java
复制代码
SELECT a FROM Admin a WHERE a.username = :username
参数
String username
:这是方法的参数,它会被用作查询条件,查询中的:username
就是传给这个方法的值。
返回类型
Admin
:这个方法的返回类型是Admin
类的一个实例。这表示查询预期返回一个单一的结果。如果查询结果为空,则返回null
。如果查询返回多个结果,通常会抛出异常,例如IncorrectResultSizeDataAccessException
。
自定义查询语句的使用
虽然方法名查询非常强大且易于使用,但有时你可能需要执行更复杂的查询,这些查询可能无法通过方法名直接表示。此时,你可以使用 @Query
注解来定义自定义的 JPQL 或 SQL 查询。
使用 @Query 注解
例如,如果你想根据 username
搜索但不区分大小写,可以这样做:
java
复制代码
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface AdminRepository extends JpaRepository<Admin, Long> {
@Query("SELECT a FROM Admin a WHERE LOWER(a.username) = LOWER(:username)")
Admin findByUsernameIgnoreCase(@Param("username") String username);
}
使用原生 SQL 查询
如果你需要使用原生 SQL 语句而不是 JPQL,可以将 nativeQuery
属性设置为 true
:
@Query(value = "SELECT * FROM admins WHERE LOWER(username) = LOWER(:username)", nativeQuery = true)
Admin findByUsernameIgnoreCaseNative(@Param("username") String username);
注意事项
使用自定义查询时,确保:
- 字段名和参数名正确无误,避免拼写错误。
- 使用
@Param
注解确保查询参数名称的一致性。 - 考虑查询的性能和优化,特别是在使用原生 SQL 时。
- 注意数据安全,特别是在拼接字符串构造查询时,防止 SQL 注入等安全风险。
通过这种方式,Spring Data JPA 允许开发者以非常灵活和强大的方式来操作数据库,既保持了简单性,也提供了扩展性。
3.定义service类
Service 层
Service
层位于 数据访问层(dao)和控制器(controller)之间,负责处理业务逻辑。这一层会使用
Repository 层提供的方法来访问和修改数据。
Service` 层的好处是它将业务逻辑与数据访问代码分离,使得业务逻辑可以独立于数据库的具体实现。这种分离也使得业务逻辑更容易被测试和重用。
在你的例子中,AdminService
类包含了对 Admin
实体的操作,如查询所有管理员、保存或更新管理员信息、以及删除管理员。它通过注入 AdminRepository
来实现这些功能:
@Service
public class AdminService {
@Autowired
private AdminRepository adminRepository;
public List<Admin> findAll() {
return adminRepository.findAll();
}
public Admin save(Admin admin) {
return adminRepository.save(admin);
}
public Admin update(Admin admin) {
return adminRepository.save(admin); // 注意:save 方法在 JPA 中既用于保存新实体也用于更新现有实体
}
public void delete(Admin admin) {
adminRepository.delete(admin);
}
}
关联和好处
- 解耦和重用性:
Service
层使得业务逻辑可以从数据访问逻辑中解耦,增加了代码的重用性。 - 事务管理:在
Service
层处理事务通常更合理,因为业务逻辑可能涉及多个步骤,每个步骤可能需要执行多个数据库操作。通过在Service
层控制事务,可以确保数据的一致性和完整性。 - 灵活性:如果将来需要更换底层数据库或修改数据访问技术,你只需要更改
Repository
层的实现而不需要修改业务逻辑。 - 单一职责原则:遵循单一职责原则,
Repository
层专注于数据访问,而Service
层专注于业务逻辑,使得系统的每部分都不会过于复杂,易于管理和扩展。
4.控制器(controller)层
代码块:
以上代码定义了一个名为 LoginController
的 Spring MVC 控制器,负责处理与登录相关的 HTTP 请求。这个控制器使用了几个关键的 Spring 框架特性来实现其功能。下面是对这段代码的详细分析:
导入的类:
import org.example.login.model.Admin;
import org.example.login.dao.AdminRepository;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
- Admin: 这是一个模型类,代表系统的管理员。
- AdminRepository: 这是一个数据访问对象(DAO),特定于
Admin
类,用于数据库操作。 - Autowired: Spring 的注解,用于依赖注入。
- Controller: 标记该类为 Spring MVC 控制器。
- Model: 用于在控制器和视图之间传递数据。
- GetMapping 和 PostMapping: 注解,用于处理 HTTP GET 和 POST 请求。
类和方法:
@Controller
public class LoginController {
@Autowired
private AdminRepository adminRepository;
- @Controller: 表明这个类是一个 Spring MVC 的控制器。
- @Autowired: 自动注入
AdminRepository
的实例,这避免了需要手动创建实例的需求,简化了代码并增强了模块化。
登录页面请求处理:
@GetMapping("/login")
public String login() {
return "login";
}
- @GetMapping(“/login”): 定义一个方法来处理对
/login
路径的 GET 请求。该方法返回 “login” 字符串,指向一个名为 “login” 的视图(通常是一个 HTML 文件)。
提交登录表单的请求处理
- @PostMapping(“/login”): 定义一个方法来处理对
/login
路径的 POST 请求。此方法接收来自登录表单的username
和password
。 - @RequestParam(“username”) 和 @RequestParam(“password”): 这些注解用于从 POST 请求中获取名为 “username” 和 “password” 的参数。
- Model model:
Model
对象用于在控制器和视图之间传递数据。在这种情况下,用来传递错误信息。
登录验证逻辑
@PostMapping("/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Model model) {
Admin admin = adminRepository.findByUsername(username);
if (admin != null && admin.getPassword().equals(password)) {
return "redirect:/login/admin";
} else {
model.addAttribute("error", "Invalid username or password.");
return "login";
}
}
- Admin admin=adminRepository.findByUsername(username): 通过用户名查询数据库以获取
Admin
对象。 - if (admin != null && admin.getPassword().equals(password)): 检查数据库中是否存在该用户名的管理员,并且密码是否匹配。
- return “redirect:/login/admin”: 如果用户名和密码验证成功,重定向到
/login/admin
。这通常指向一个新的控制器方法,该方法处理登录成功后的页面或操作。
- return “redirect:/login/admin”: 如果用户名和密码验证成功,重定向到
- else:
- model.addAttribute(“error”, “Invalid username or password.”): 如果验证失败(即用户名不存在或密码不匹配),在模型中添加一个错误信息。这个错误信息可以在登录视图中显示,以通知用户。
- return “login”: 重新返回登录视图,允许用户再次尝试登录。
@RequestParam
是一个 Spring MVC 注解,用于将 HTTP 请求中的请求参数绑定到控制器方法的参数上。这个注解非常有用,因为它允许你直接在方法签名中访问请求中的特定参数,而无需手动解析查询字符串或表单数据。下面是关于 @RequestParam
的一些关键用法和特性:
在 Spring MVC 控制器的方法中,你可以使用 @RequestParam
来提取请求参数。例如,如果你的 HTTP 请求是这样的 /search?name=example
,你可以使用 @RequestParam
来获取 name
参数的值:
@GetMapping("/search")
public String search(@RequestParam("name") String name) {
// 使用 name 参数的值进行一些操作
return "result";
}
登陆成功后跳转到/login/admin,返回adminHome视图
if (admin != null && admin.getPassword().equals(password)) {
return "redirect:/login/admin";
}
@Controller
@RequestMapping("/login")
public class AdminHome {
@GetMapping("/admin")
public String admin() {
return "adminHome";
}
}
总结
这段控制器代码简洁地展示了如何使用 Spring MVC,Spring Data JPA,和模型数据来处理基本的登录流程。它处理了用户输入,进行了身份验证,并根据验证结果给予了反馈。这是典型的 Web 应用程序中的用户认证流程的实现方式。
5.Thymeleaf 模板文件
login.html和adminHome.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<title>Admin Login</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}">
</head>
<body>
<div class="container">
<header>
<h1>Admin Login</h1>
</header>
<form th:action="@{/login}" method="post">
<div>
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
</div>
<div>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
</div>
<div>
<button type="submit">Login</button>
</div>
<div th:if="${error}">
<p th:text="${error}" style="color: red;"></p>
</div>
</form>
</div>
</body>
</html>
模板文件(adminHome.html 和 login.html):这些 HTML 文件通过 Thymeleaf 模板引擎处理,可以动态生成 HTML 内容并发送给客户端。Thymeleaf 允许在 HTML 文件中直接写入 Spring 表达式和命令,这些命令在运行时会被解析和执行,从而根据服务器端的数据动态地改变 HTML 内容。
6.登陆界面
输入localhost:8080/login成功跳到login.html视图
admin数据表
输入账户密码后成功跳到login/admin,并返回adminHome视图
结束:
以上代码使用data_jpa实现了一个最基础的用户登陆,在这基础上可以扩展为各种管理系统等,能够优化大量代码,很适合数据库操作。