本文目录导读:

我来为您介绍一个完整的Java注册功能实现案例,包含前后端交互。
后端实现(Spring Boot)
实体类
// User.java
package com.example.demo.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
private String email;
private String phone;
@Column(name = "create_time")
private LocalDateTime createTime;
// getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public LocalDateTime getCreateTime() { return createTime; }
public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
}
DTO(数据传输对象)
// RegisterRequest.java
package com.example.demo.dto;
import javax.validation.constraints.*;
public class RegisterRequest {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度3-20个字符")
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
private String username;
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度6-20个字符")
private String password;
@Email(message = "邮箱格式不正确")
private String email;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
// getters and setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
}
响应类
// ApiResponse.java
package com.example.demo.dto;
public class ApiResponse<T> {
private int code;
private String message;
private T data;
public ApiResponse(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(200, "success", data);
}
public static <T> ApiResponse<T> error(int code, String message) {
return new ApiResponse<>(code, message, null);
}
// getters
public int getCode() { return code; }
public String getMessage() { return message; }
public T getData() { return data; }
}
Repository层
// UserRepository.java
package com.example.demo.repository;
import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByUsername(String username);
boolean existsByEmail(String email);
boolean existsByPhone(String phone);
}
Service层
// UserService.java
package com.example.demo.service;
import com.example.demo.dto.RegisterRequest;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
/**
* 用户注册
*/
public User register(RegisterRequest request) {
// 检查用户名是否已存在
if (userRepository.existsByUsername(request.getUsername())) {
throw new RuntimeException("用户名已存在");
}
// 检查邮箱是否已存在
if (request.getEmail() != null && userRepository.existsByEmail(request.getEmail())) {
throw new RuntimeException("邮箱已被注册");
}
// 检查手机号是否已存在
if (request.getPhone() != null && userRepository.existsByPhone(request.getPhone())) {
throw new RuntimeException("手机号已被注册");
}
// 创建新用户
User user = new User();
user.setUsername(request.getUsername());
user.setPassword(passwordEncoder.encode(request.getPassword())); // 密码加密
user.setEmail(request.getEmail());
user.setPhone(request.getPhone());
user.setCreateTime(LocalDateTime.now());
return userRepository.save(user);
}
}
Controller层
// UserController.java
package com.example.demo.controller;
import com.example.demo.dto.ApiResponse;
import com.example.demo.dto.RegisterRequest;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping("/api/user")
@CrossOrigin(origins = "*") // 允许跨域
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public ResponseEntity<ApiResponse<User>> register(@Valid @RequestBody RegisterRequest request) {
try {
User user = userService.register(request);
return ResponseEntity.ok(ApiResponse.success(user));
} catch (RuntimeException e) {
return ResponseEntity.badRequest()
.body(ApiResponse.error(400, e.getMessage()));
}
}
}
安全配置
// SecurityConfig.java
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
public class SecurityConfig {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
前端实现(HTML + JavaScript)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">用户注册</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.register-container {
background: white;
border-radius: 10px;
padding: 40px;
width: 400px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
}
h2 {
text-align: center;
color: #333;
margin-bottom: 30px;
font-size: 28px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #555;
font-size: 14px;
font-weight: 500;
}
input {
width: 100%;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
transition: border-color 0.3s;
}
input:focus {
outline: none;
border-color: #667eea;
}
input.error {
border-color: #e74c3c;
}
.error-message {
color: #e74c3c;
font-size: 12px;
margin-top: 5px;
display: none;
}
.error-message.show {
display: block;
}
button {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s;
}
button:hover {
transform: translateY(-2px);
}
button:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.message {
margin-top: 20px;
padding: 10px;
border-radius: 5px;
display: none;
}
.message.success {
display: block;
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.message.error {
display: block;
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.password-strength {
height: 5px;
margin-top: 5px;
border-radius: 3px;
transition: all 0.3s;
}
.password-strength.weak {
width: 33%;
background: #e74c3c;
}
.password-strength.medium {
width: 66%;
background: #f39c12;
}
.password-strength.strong {
width: 100%;
background: #27ae60;
}
</style>
</head>
<body>
<div class="register-container">
<h2>用户注册</h2>
<form id="registerForm">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" name="username"
placeholder="3-20位字母、数字或下划线" required>
<div class="error-message" id="usernameError"></div>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password"
placeholder="6-20位字符" required>
<div class="password-strength" id="passwordStrength"></div>
<div class="error-message" id="passwordError"></div>
</div>
<div class="form-group">
<label for="confirmPassword">确认密码</label>
<input type="password" id="confirmPassword" name="confirmPassword"
placeholder="再次输入密码" required>
<div class="error-message" id="confirmPasswordError"></div>
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" id="email" name="email"
placeholder="请输入邮箱地址">
<div class="error-message" id="emailError"></div>
</div>
<div class="form-group">
<label for="phone">手机号</label>
<input type="tel" id="phone" name="phone"
placeholder="请输入11位手机号">
<div class="error-message" id="phoneError"></div>
</div>
<button type="submit" id="submitBtn">注册</button>
</form>
<div class="message" id="message"></div>
</div>
<script>
// 获取DOM元素
const form = document.getElementById('registerForm');
const username = document.getElementById('username');
const password = document.getElementById('password');
const confirmPassword = document.getElementById('confirmPassword');
const email = document.getElementById('email');
const phone = document.getElementById('phone');
const submitBtn = document.getElementById('submitBtn');
const message = document.getElementById('message');
// 实时验证
username.addEventListener('blur', validateUsername);
password.addEventListener('input', validatePassword);
confirmPassword.addEventListener('blur', validateConfirmPassword);
email.addEventListener('blur', validateEmail);
phone.addEventListener('blur', validatePhone);
// 密码强度检测
password.addEventListener('input', function() {
const strength = document.getElementById('passwordStrength');
const value = this.value;
if (value.length === 0) {
strength.className = 'password-strength';
return;
}
let score = 0;
if (value.length >= 6) score++;
if (value.length >= 10) score++;
if (/[a-z]/.test(value)) score++;
if (/[A-Z]/.test(value)) score++;
if (/[0-9]/.test(value)) score++;
if (/[^a-zA-Z0-9]/.test(value)) score++;
if (score <= 2) {
strength.className = 'password-strength weak';
} else if (score <= 4) {
strength.className = 'password-strength medium';
} else {
strength.className = 'password-strength strong';
}
});
// 验证用户名
function validateUsername() {
const error = document.getElementById('usernameError');
const value = username.value;
if (!value) {
showError(username, error, '用户名不能为空');
return false;
}
if (!/^[a-zA-Z0-9_]{3,20}$/.test(value)) {
showError(username, error, '用户名格式不正确(3-20位字母、数字或下划线)');
return false;
}
hideError(username, error);
return true;
}
// 验证密码
function validatePassword() {
const error = document.getElementById('passwordError');
const value = password.value;
if (!value) {
showError(password, error, '密码不能为空');
return false;
}
if (value.length < 6 || value.length > 20) {
showError(password, error, '密码长度需在6-20位之间');
return false;
}
hideError(password, error);
return true;
}
// 验证确认密码
function validateConfirmPassword() {
const error = document.getElementById('confirmPasswordError');
const value = confirmPassword.value;
if (!value) {
showError(confirmPassword, error, '请确认密码');
return false;
}
if (value !== password.value) {
showError(confirmPassword, error, '两次密码不一致');
return false;
}
hideError(confirmPassword, error);
return true;
}
// 验证邮箱
function validateEmail() {
const error = document.getElementById('emailError');
const value = email.value;
if (!value) return true; // 邮箱可选
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
showError(email, error, '邮箱格式不正确');
return false;
}
hideError(email, error);
return true;
}
// 验证手机号
function validatePhone() {
const error = document.getElementById('phoneError');
const value = phone.value;
if (!value) return true; // 手机号可选
if (!/^1[3-9]\d{9}$/.test(value)) {
showError(phone, error, '手机号格式不正确');
return false;
}
hideError(phone, error);
return true;
}
// 显示错误
function showError(input, errorElement, message) {
input.classList.add('error');
errorElement.textContent = message;
errorElement.classList.add('show');
}
// 隐藏错误
function hideError(input, errorElement) {
input.classList.remove('error');
errorElement.textContent = '';
errorElement.classList.remove('show');
}
// 提交表单
form.addEventListener('submit', async function(e) {
e.preventDefault();
// 验证所有字段
const isUsernameValid = validateUsername();
const isPasswordValid = validatePassword();
const isConfirmPasswordValid = validateConfirmPassword();
const isEmailValid = validateEmail();
const isPhoneValid = validatePhone();
if (!isUsernameValid || !isPasswordValid || !isConfirmPasswordValid ||
!isEmailValid || !isPhoneValid) {
return;
}
// 准备请求数据
const data = {
username: username.value,
password: password.value,
email: email.value || null,
phone: phone.value || null
};
// 禁用按钮,显示加载状态
submitBtn.disabled = true;
submitBtn.textContent = '注册中...';
message.className = 'message';
try {
const response = await fetch('http://localhost:8080/api/user/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (response.ok && result.code === 200) {
showMessage('注册成功!正在跳转到登录页面...', 'success');
setTimeout(() => {
window.location.href = '/login.html';
}, 2000);
} else {
showMessage(result.message || '注册失败', 'error');
}
} catch (error) {
showMessage('网络错误,请稍后重试', 'error');
console.error('注册错误:', error);
} finally {
submitBtn.disabled = false;
submitBtn.textContent = '注册';
}
});
// 显示消息
function showMessage(text, type) {
message.textContent = text;
message.className = `message ${type}`;
// 3秒后自动隐藏成功消息
if (type === 'success') {
setTimeout(() => {
message.className = 'message';
}, 3000);
}
}
</script>
</body>
</html>
application.yml配置
# application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
依赖配置
<!-- pom.xml 关键依赖 -->
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 数据验证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- 密码加密 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
</dependencies>
测试用例
// UserServiceTest.java
@SpringBootTest
@AutoConfigureMockMvc
class UserServiceTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setUp() {
userRepository.deleteAll();
}
@Test
void testRegisterSuccess() throws Exception {
String requestBody = "{\"username\":\"testuser\",\"password\":\"123456\"," +
"\"email\":\"test@example.com\",\"phone\":\"13800138000\"}";
mockMvc.perform(post("/api/user/register")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
}
@Test
void testRegisterDuplicateUsername() throws Exception {
// 先注册一个用户
User existingUser = new User();
existingUser.setUsername("testuser");
existingUser.setPassword("password");
userRepository.save(existingUser);
String requestBody = "{\"username\":\"testuser\",\"password\":\"123456\"}";
mockMvc.perform(post("/api/user/register")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").value("用户名已存在"));
}
}
这个注册功能案例包括了:
-
后端实现:
- 实体类设计
- 数据验证
- 密码加密
- 异常处理
- RESTful API
-
前端实现:
- 表单验证
- 实时密码强度检测
- AJAX请求
- 用户友好的错误提示
-
安全考虑:
- 密码加密存储
- 输入验证
- 防止SQL注入
- 跨域配置
-
用户体验:
- 实时验证反馈
- 密码强度指示器
- 加载状态提示
- 错误信息友好显示
运行项目后,访问 http://localhost:8080/register.html 即可测试注册功能。