You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot应用无法从数据库获取用户数据填充HTML表格问题

问题:SpringBoot应用无法将数据库用户表数据展示到HTML表格

数据库已成功连接,但HTML页面无法获取并填充用户数据。以下是相关代码:

User实体类

package com.example.hardware_inventory.model;

public class User {
    private Long userId;
    private String username;
    private String passwordHash;
    private String role;

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getPasswordHash() {
        return passwordHash;
    }

    public void setPasswordHash(String passwordHash) {
        this.passwordHash = passwordHash;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    // getters and setters
}

User Repository类

package com.example.hardware_inventory.repository;

import com.example.hardware_inventory.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import org.springframework.dao.EmptyResultDataAccessException;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;

@Repository
public class UserRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static final class UserRowMapper implements RowMapper<User> {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setUserId(rs.getLong("user_id"));
            user.setUsername(rs.getString("username"));
            user.setPasswordHash(rs.getString("password_hash"));
            user.setRole(rs.getString("role"));
            return user;
        }
    }

    public List<User> findAll() {
        String sql = "SELECT * FROM users";
        return jdbcTemplate.query(sql, new UserRowMapper());
    }

    public Optional<User> findById(Long id) {
        String sql = "SELECT * FROM users WHERE user_id = ?";
        try {
            return Optional.ofNullable(jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper()));
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }

    public Optional<User> findByUsername(String username) {
        String sql = "SELECT * FROM users WHERE username = ?";
        try {
            return Optional.ofNullable(jdbcTemplate.queryForObject(sql, new Object[]{username}, new UserRowMapper()));
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }

    public void save(User user) {
        String sql = "INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)";
        jdbcTemplate.update(sql, user.getUsername(), user.getPasswordHash(), user.getRole());
    }

    public void update(User user) {
        String sql = "UPDATE users SET username = ?, password_hash = ?, role = ? WHERE user_id = ?";
        jdbcTemplate.update(sql, user.getUsername(), user.getPasswordHash(), user.getRole(), user.getUserId());
    }

    public void deleteById(Long id) {
        String sql = "DELETE FROM users WHERE user_id = ?";
        jdbcTemplate.update(sql, id);
    }
    public void resetPassword(Long id, String newPassword) {
        String sql = "UPDATE users SET password_hash = ? WHERE user_id = ?";
        jdbcTemplate.update(sql, newPassword, id);
    }

    public void blockUser(Long id) {
        String sql = "UPDATE users SET role = 'blocked' WHERE user_id = ?";
        jdbcTemplate.update(sql, id);
    }
}

User Service类

package com.example.hardware_inventory.service;

import com.example.hardware_inventory.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public void resetPassword(Long id, String newPassword) {
        userRepository.resetPassword(id, newPassword);
    }

    public void blockUser(Long id) {
        userRepository.blockUser(id);
    }
}

前端HTML页面(add_new_user.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Add New User</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="form-container">
    <h1>Add New User</h1>
    <form id="add-user-form">
        <input type="text" id="new-username" placeholder="Username" required>
        <input type="password" id="new-password" placeholder="Password" required>
        <select id="role">
            <option value="user">User</option>
            <option value="admin">Admin</option>
        </select>
        <button type="submit">Add User</button>
    </form>
</div>

<div class="table-container">
    <h1>All Users</h1>
    <table id="users-table">
        <thead>
        <tr>
            <th>User ID</th>
            <th>Username</th>
            <th>Role</th>
            <th>Actions</th>
        </tr>
        </thead>
        <tbody>
        <!-- Dynamic rows will be inserted here -->
        </tbody>
    </table>
</div>

<script src="scripts.js"></script>
</body>
</html>

前端JavaScript代码(scripts.js)

document.addEventListener('DOMContentLoaded', function() {
    const form = document.getElementById('add-user-form');
    const usersTable = document.getElementById('users-table').getElementsByTagName('tbody')[0];

    // Fetch users and display them
    fetch('/api/users')
        .then(response => response.json())
        .then(data => {
            data.forEach(user => {
                addUserRow(user);
            });
        });

    // Handle form submission
    form.addEventListener('submit', function(event) {
        event.preventDefault();

        const newUsername = document.getElementById('new-username').value;
        const newPassword = document.getElementById('new-password').value;
        const role = document.getElementById('role').value;

        fetch('/api/users', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                username: newUsername,
                password: newPassword,
                role: role
            })
        })
        .then(response => response.json())
        .then(user => {
            addUserRow(user);
            form.reset();
        });
    });

    function addUserRow(user) {
        const row = usersTable.insertRow();

        const cellId = row.insertCell(0);
        const cellUsername = row.insertCell(1);
        const cellRole = row.insertCell(2);
        const cellActions = row.insertCell(3);

        cellId.textContent = user.userId;
        cellUsername.textContent = user.username;
        cellRole.textContent = user.role;
        cellActions.innerHTML = `<form action="/api/users/delete/${user.userId}" method="post">
                                    <button type="submit">Delete</button>
                                 </form>`;
    }
});

排查和修复步骤

  1. 添加缺失的REST控制器(核心问题)
    前端发起的/api/users请求没有对应的后端接口处理,这是无法获取数据的关键原因。添加如下Controller:

    package com.example.hardware_inventory.controller;
    
    import com.example.hardware_inventory.model.User;
    import com.example.hardware_inventory.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.List;
    
    @RestController
    @RequestMapping("/api/users")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        // 获取所有用户
        @GetMapping
        public List<User> getAllUsers() {
            return userService.getAllUsers();
        }
    
        // 添加新用户
        @PostMapping
        public ResponseEntity<User> createUser(@RequestBody User user) {
            // 实际项目需加密密码,此处仅示例
            userService.saveUser(user);
            // 需修改UserService添加saveUser方法,或直接调用Repository
            return ResponseEntity.status(HttpStatus.CREATED).body(user);
        }
    
        // 删除用户
        @PostMapping("/delete/{id}")
        public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
            userService.deleteUser(id);
            return ResponseEntity.ok().build();
        }
    
        // 补充重置密码、封禁用户接口
        @PostMapping("/reset-password/{id}")
        public ResponseEntity<Void> resetPassword(@PathVariable Long id, @RequestParam String newPassword) {
            userService.resetPassword(id, newPassword);
            return ResponseEntity.ok().build();
        }
    
        @PostMapping("/block/{id}")
        public ResponseEntity<Void> blockUser(@PathVariable Long id) {
            userService.blockUser(id);
            return ResponseEntity.ok().build();
        }
    }
    
  2. 完善UserService的查询与保存方法
    当前Service缺少获取所有用户和保存用户的方法,补充如下:

    @Service
    public class UserService {
    
        @Autowired
        private UserRepository userRepository;
    
        public List<User> getAllUsers() {
            return userRepository.findAll();
        }
    
        public void saveUser(User user) {
            userRepository.save(user);
        }
    
        public void deleteUser(Long id) {
            userRepository.deleteById(id);
        }
    
        // 已有方法...
    }
    
  3. 修复前后端字段不匹配问题
    前端POST请求发送的是password,但实体类对应字段是passwordHash,修改JS请求体:

    body: JSON.stringify({
        username: newUsername,
        passwordHash: newPassword, // 与实体类字段名统一
        role: role
    })
    
  4. 添加前端错误调试
    为fetch请求添加错误捕获,便于定位问题:

    fetch('/api/users')
        .then(response => {
            if (!response.ok) throw new Error(`请求失败,状态码:${response.status}`);
            return response.json();
        })
        .then(data => {
            data.forEach(user => addUserRow(user));
        })
        .catch(error => console.error('获取用户列表失败:', error));
    
  5. 密码存储安全优化
    不要存储明文密码,使用BCrypt加密:

    // 在配置类中声明加密Bean
    @Configuration
    public class SecurityConfig {
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    
    // 在保存用户时加密
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    
    public void saveUser(User user) {
        user.setPasswordHash(passwordEncoder.encode(user.getPasswordHash()));
        userRepository.save(user);
    }
    

内容的提问来源于stack exchange,提问作者N P Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 23:45:54