利于springboot构建项目,加入start_datajpa、web、thymeleaf、mysql_connector_j等maven依赖。
创建实体类(model),服务层(service),控制器(controller),数据访问层(dao)
源码:https://github.com/wuzerui378/login_UI
@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:使用特定的数据库表来模拟序列生成主键。这种策略不依赖于数据库的特定特性,因此在所有数据库中都可用,但可能在高并发时性能较低。
@Repository
public interface AdminRepository extends JpaRepository {
Admin findByUsername(String username);
}
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 查询。
例如,如果你想根据 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 {
@Query("SELECT a FROM Admin a WHERE LOWER(a.username) = LOWER(:username)")
Admin findByUsernameIgnoreCase(@Param("username") String username);
}
如果你需要使用原生 SQL 语句而不是 JPQL,可以将 nativeQuery 属性设置为 true:
@Query(value = "SELECT * FROM admins WHERE LOWER(username) = LOWER(:username)", nativeQuery = true)
Admin findByUsernameIgnoreCaseNative(@Param("username") String username);
使用自定义查询时,确保:
@Param 注解确保查询参数名称的一致性。通过这种方式,Spring Data JPA 允许开发者以非常灵活和强大的方式来操作数据库,既保持了简单性,也提供了扩展性。
Service 层位于 数据访问层(dao)和控制器(controller)之间,负责处理业务逻辑。这一层会使用 Repository 层提供的方法来访问和修改数据。Service` 层的好处是它将业务逻辑与数据访问代码分离,使得业务逻辑可以独立于数据库的具体实现。这种分离也使得业务逻辑更容易被测试和重用。
在你的例子中,AdminService 类包含了对 Admin 实体的操作,如查询所有管理员、保存或更新管理员信息、以及删除管理员。它通过注入 AdminRepository 来实现这些功能:
@Service
public class AdminService {
@Autowired
private AdminRepository adminRepository;
public List 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 层专注于业务逻辑,使得系统的每部分都不会过于复杂,易于管理和扩展。以上代码定义了一个名为 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 类,用于数据库操作。@Controller
public class LoginController {
@Autowired
private AdminRepository adminRepository;
AdminRepository 的实例,这避免了需要手动创建实例的需求,简化了代码并增强了模块化。@GetMapping("/login")
public String login() {
return "login";
}
/login 路径的 GET 请求。该方法返回 “login” 字符串,指向一个名为 “login” 的视图(通常是一个 HTML 文件)。/login 路径的 POST 请求。此方法接收来自登录表单的 username 和 password。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 对象。/login/admin。这通常指向一个新的控制器方法,该方法处理登录成功后的页面或操作。@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 应用程序中的用户认证流程的实现方式。
<!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 内容。
输入localhost:8080/login成功跳到login.html视图

admin数据表

输入账户密码后成功跳到login/admin,并返回adminHome视图


以上代码使用data_jpa实现了一个最基础的用户登陆,在这基础上可以扩展为各种管理系统等,能够优化大量代码,很适合数据库操作。