扩展:构建ssm项目,使用ajax请求实现layui单表的查询和添加

'# 扩展:构建SSM项目,使用Ajax请求实现layui单表的查询和添加

一、背景与问题

在企业级开发中,SSM框架(Spring + Spring MVC + MyBatis)因其成熟稳定的特点,仍然是主流的Java Web开发方案。而layui作为国内优秀的前端框架,因其模块化、组件化的特点,广泛应用于管理后台系统。在实际开发中,单表的查询和添加操作是基础功能,但传统的页面刷新方式存在明显的用户体验短板。

本篇将深入探讨如何通过Ajax技术实现layui单表的无刷新查询和添加功能,重点分析其工作原理、实现细节、性能优化方案以及常见问题的解决方案。

二、基本原理

1. Ajax请求机制

Ajax(Asynchronous JavaScript and XML)通过XMLHttpRequest对象实现异步通信,核心流程包括:

  • 前端通过JavaScript发送异步请求
  • 后端接收请求并处理业务逻辑
  • 后端返回JSON数据
  • 前端解析数据并更新DOM

2. layui表格组件特性

layui的table模块支持:

  • 异步加载数据(通过layui.use初始化)
  • 动态更新数据(通过table.reload方法)
  • 自定义列模板(templet属性)
  • 分页控制(page参数)

3. 跨域处理

当前后端分离时,需配置CORS(跨域资源共享)策略,主要通过以下方式实现:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .exposedHeaders("Content-Type")
                .allowCredentials(true);
    }
}

三、环境准备

1. 项目依赖(Spring Boot 2.7 + MyBatis Plus)

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
</dependencies>

2. 前端依赖(layui 2.6.8)

<link href="https://www.layui.org/css/layui.css" rel="stylesheet">
<script src="https://www.layui.org/layui.js"></script>

四、核心实现

1. 前端页面(layui单表查询)

<div class="layui-container">
    <button class="layui-btn" id="addBtn">添加用户</button>
    <table id="userTable" lay-filter="userTable"></table>
</div>

<script>
layui.use(['table', 'form'], function(){
    var table = layui.table;
    var $ = layui.$;

    // 查询接口
    function queryUsers(page, limit) {
        $.ajax({
            url: '/api/users',
            type: 'GET',
            data: {page: page, limit: limit},
            success: function(res){
                table.reload('userTable', {
                    page: {curr: page},
                    data: res.data
                });
            }
        });
    }

    // 初始化表格
    table.render({
        elem: '#userTable',
        url: '/api/users',
        cols: [[ 
            {type: 'checkbox'},
            {field: 'id', title: 'ID'},
            {field: 'name', title: '姓名'},
            {field: 'email', title: '邮箱'}
        ]],
        page: true
    });

    // 添加按钮事件
    $('#addBtn').on('click', function(){
        layer.open({
            type: 1,
            area: ['500px', '300px'],
            content: '<div><input type="text" id="name" placeholder="姓名"><br>'+
                     '<input type="email" id="email" placeholder="邮箱"><br>'+
                     '<button id="submitBtn">提交</button></div>'
        });
        
        $('#submitBtn').on('click', function(){
            $.ajax({
                url: '/api/users',
                type: 'POST',
                data: {
                    name: $('#name').val(),
                    email: $('#email').val()
                },
                success: function(res){
                    layer.msg('添加成功');
                    queryUsers(1, 10);
                }
            });
        });
    });
});
</script>

2. 后端接口实现(Spring Boot)

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public Result queryUsers(@RequestParam int page, @RequestParam int limit) {
        return Result.success(userService.pageQuery(page, limit));
    }

    @PostMapping
    public Result addUser(@RequestBody User user) {
        return Result.success(userService.addUser(user));
    }
}

3. 服务层实现(MyBatis Plus)

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public Page<User> pageQuery(int page, int limit) {
        Page<User> pageQuery = new Page<>(page, limit);
        return userMapper.selectPage(pageQuery, null);
    }

    public boolean addUser(User user) {
        return userMapper.insert(user) > 0;
    }
}

五、完整案例

1. 数据库表结构

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE
);

2. 完整项目结构

src
├── main
│   ├── java
│   │   └── com.example.ssm
│   │       ├── controller
│   │       │   └── UserController.java
│   │       ├── service
│   │       │   ├── UserService.java
│   │       │   └── impl
│   │       │       └── UserServiceImpl.java
│   │       └── mapper
│   │           └── UserMapper.java
│   └── resources
│       └── application.yml

3. 完整前端页面(带分页)

<div class="layui-container">
    <button class="layui-btn" id="addBtn">添加用户</button>
    <table id="userTable" lay-filter="userTable"></table>
</div>

<script>
layui.use(['table', 'form', 'laypage'], function(){
    var table = layui.table;
    var laypage = layui.laypage;
    var $ = layui.$;

    var currentPage = 1;
    var pageSize = 10;

    // 查询接口
    function queryUsers(page) {
        $.ajax({
            url: '/api/users',
            type: 'GET',
            data: {page: page, limit: pageSize},
            success: function(res){
                table.reload('userTable', {
                    page: {curr: page},
                    data: res.data
                });
                laypage.render({
                    elem: 'pageDiv',
                    count: res.total,
                    limit: pageSize,
                    curr: page,
                    layout: ['count', 'prev', 'page', 'next', 'limit'],
                    jump: function(obj, first){
                        if(!first){
                            queryUsers(obj.curr);
                        }
                    }
                });
            }
        });
    }

    // 初始化表格
    table.render({
        elem: '#userTable',
        url: '/api/users',
        cols: [[ 
            {type: 'checkbox'},
            {field: 'id', title: 'ID'},
            {field: 'name', title: '姓名'},
            {field: 'email', title: '邮箱'}
        ]],
        page: true
    });

    // 添加按钮事件
    $('#addBtn').on('click', function(){
        layer.open({
            type: 1,
            area: ['500px', '300px'],
            content: '<div><input type="text" id="name" placeholder="姓名"><br>'+
                     '<input type="email" id="email" placeholder="邮箱"><br>'+
                     '<button id="submitBtn">提交</button></div>'
        });
        
        $('#submitBtn').on('click', function(){
            $.ajax({
                url: '/api/users',
                type: 'POST',
                data: {
                    name: $('#name').val(),
                    email: $('#email').val()
                },
                success: function(res){
                    layer.msg('添加成功');
                    queryUsers(1);
                }
            });
        });
    });
});
</script>

六、源码解析

1. 分页参数传递

在前端通过URL参数传递分页信息:

data: {page: page, limit: pageSize}

后端接收时使用:

@GetMapping
public Result queryUsers(@RequestParam int page, @RequestParam int limit)

2. 数据格式处理

后端返回的JSON结构:

{
  "code": 0,
  "msg": "success",
  "data": [
    {"id": 1, "name": "张三", "email": "zhangsan@example.com"},
    ...
  ],
  "total": 100
}

3. 异常处理

在Controller中添加全局异常处理:

@ExceptionHandler
public Result handleException(Exception e) {
    return Result.error("系统错误:" + e.getMessage());
}

七、进阶使用

1. 复杂查询支持

通过layui的where参数支持条件查询:

layui.use('table', function(){
    var table = layui.table;
    
    table.render({
        elem: '#userTable',
        url: '/api/users',
        where: { status: 1 }
    });
});

2. 分页优化

使用PageHelper插件实现分页:

@Auto
public class PageHelperConfig {
    @Bean
    public PageInterceptor pageInterceptor() {
        return new PageInterceptor();
    }
}

3. 数据校验

使用Hibernate Validator进行参数校验:

public class User {
    @NotNull(message = "姓名不能为空")
    private String name;
    
    @Email(message = "邮箱格式不正确")
    private String email;
}

八、性能与工程实践

1. 性能优化方案

  • 启用MyBatis Plus的SQL日志:

    mybatis-plus:
    configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutLogger
  • 使用缓存减少数据库访问:

    @Cacheable(value = "users", key = "#page + ':' + #limit")
    public Page<User> pageQuery(int page, int limit) {
      ...
    }

2. 安全风险分析

  • SQL注入:使用预编译语句(MyBatis默认支持)
  • 跨站攻击:配置CORS策略
  • 数据篡改:使用HTTPS传输数据

3. 异常处理机制

  • 前端使用try-catch捕获异常
  • 后端统一返回错误码和错误信息

    $.ajax({
      url: '/api/users',
      type: 'POST',
      data: { ... },
      error: function(xhr, status, error) {
          console.error('请求失败:', status, error);
      }
    });

九、常见问题与踩坑

1. 跨域问题

错误表现:浏览器控制台提示"Blocked by CORS policy"
解决办法:

  • 后端配置CORS
  • 使用代理服务器(如Nginx)
  • 前端添加withCredentials: false

2. 数据格式不匹配

错误表现:前端无法解析返回的JSON
解决办法:

  • 确保返回JSON格式正确
  • 使用JSON.stringify()转换数据
  • 检查Content-Type头是否为application/json

3. 分页参数传递错误

错误表现:分页后数据不正确
解决办法:

  • 确保前端传递的page参数从1开始
  • 检查后端是否处理了分页参数
  • 使用调试工具查看实际请求参数

十、最佳实践

1. 推荐方案

  • 使用分页查询替代全量查询
  • 对关键操作进行防重校验
  • 使用异步加载提高响应速度
  • 对敏感字段进行加密传输

2. 实施建议

  • 前端使用layui的table组件进行数据展示
  • 后端使用MyBatis Plus简化CRUD操作
  • 对关键业务接口添加限流保护
  • 对重要操作记录日志

十一、总结

通过本文的深入探讨,我们了解到在SSM项目中使用Ajax实现layui单表的查询和添加功能的完整方案。这种方案适用于需要频繁刷新数据但又不希望整个页面重载的场景,如数据看板、日志管理等。但需要注意以下几点:

适用场景:

  • 需要动态更新数据的管理后台
  • 需要提升用户体验的业务场景
  • 需要快速开发的中小型项目

不适用场景:

  • 需要处理大量实时数据的场景
  • 需要复杂交互的前端应用
  • 需要高度定制的UI组件

通过合理使用Ajax技术,结合layui的优秀组件,可以显著提升Web应用的性能和用户体验。同时,需要特别注意安全性、异常处理和性能优化等关键环节,确保系统的稳定性和可靠性。

最后修改于:2026年09月23日 23:47

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日