Spring Boot + Layui + Spring Data JPA 实现前后端分离下简单增删改查分页操作
1.项目背景
自己搭着玩,写个小demo
2.项目构成
后端:Spring boot 2.3(2.4不支持全局跨域配置) JDK1.8
数据库:Spring Data JPA MySQL 5.7.31
前端: Layui2.5.7
3.添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
4.配置文件application.yml
#服务端容器的配置
server:
port: 8888
#数据库配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/kaitao?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: root
#jpa配置
jpa:
show-sql: true
hibernate:
ddl-auto: update
5.导入数据库
CREATE TABLE `article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`reader` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
创建数据库:kaitao 编码:UTF-8
6.entity包
package com.godwin.entity;
import lombok.Data;
import javax.persistence.*;
/**
* 文章信息实体类
* Created by admin on 2020/12/17.
*/
@Entity
@Data
@Table(name = "article")
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String title;
private String type;
private String reader;
private String content;
}
package com.godwin.entity;
/**
* @Description: 响应消息体
* Created by admin on 2020/12/17.
*/
public class ResultBean<T> {
/**响应编码*/
private int code;
/**响应消息*/
private String msg;
/**数据总量*/
private int count;
/**数据*/
private T data;
public ResultBean() {
}
public ResultBean(int code, String msg, int count, T data) {
super();
this.code = code;
this.msg = msg;
this.count = count;
this.data = data;
}
@Override
public String toString() {
return "R [code=" + code + ", msg=" + msg + ", count=" + count + ", data=" + data + "]";
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
7.repository包(操作数据库)
package com.godwin.repository;
import com.godwin.entity.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;
/**
* 操作数据库
* Created by admin on 2020/12/17.
*/
public interface ArticleRepository extends JpaRepository<Article,Integer> {
//批量删除
@Transactional
@Modifying
@Query(value="delete from article where id in ?1 ",nativeQuery=true)
int deletes(Integer[] ids);
}
8.service包
package com.godwin.service;
import com.godwin.entity.Article;
import org.springframework.data.domain.Page;
import java.util.List;
/**
* Created by admin on 2020/12/17.
*/
public interface ArticleService {
Article save(Article article);
Article edit(Article article);
void deletes(Integer[] ids);
List<Article> findAll();
Page<Article> getPager(Integer page, Integer limit);
}
package com.godwin.service;
import com.godwin.entity.Article;
import com.godwin.repository.ArticleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by admin on 2020/12/17.
*/
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository repository;
@Override
public Article save(Article article) {
return repository.save(article);
}
@Override
public Article edit(Article article) {
return repository.save(article);
}
@Override
public void deletes(Integer[] ids) {
repository.deletes(ids);
}
@Override
public List<Article> findAll() {
return repository.findAll();
}
@Override
public Page<Article> getPager(Integer page, Integer limit) {
Pageable pageable = PageRequest.of(page-1,10);
return repository.findAll(pageable);
}
}
9.controller包
package com.godwin.controller;
import com.godwin.entity.Article;
import com.godwin.entity.ResultBean;
import com.godwin.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* Created by admin on 2020/12/17.
*/
@RestController
@RequestMapping("/kaitao")
public class ArticleController {
@Autowired
private ArticleService articleService;
@GetMapping("/list")
public ResultBean list1(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer limit){
List<Article> data = articleService.getPager(page,limit).getContent();
int count = articleService.findAll().size();
ResultBean result = new ResultBean(0,"",count,data);
return result;
}
@PostMapping("/save")
public ResultBean save(@RequestBody Article article){
// 判断是新增还是修改
if(article.getId()!=null){
articleService.edit(article);
}else{
articleService.save(article);
}
return new ResultBean(200,"",0,"");
}
@PostMapping("/remove")
public ResultBean remove(@RequestBody Integer[] ids){
articleService.deletes(ids);
return new ResultBean(200,"",0,"");
}
}
10.config(配置全局跨域)
package com.godwin.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* 添加全局跨域配置
* Created by admin on 2020/12/18.
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
}
11.前端页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>开淘网后台管理系统</title>
<link rel="stylesheet" href="layui/css/layui.css">
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo">开淘网后台管理系统</div>
<!-- 头部区域(可配合layui已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item">
<a href="">控制台</a>
</li>
<li class="layui-nav-item">
<a href="">商品管理</a>
</li>
<li class="layui-nav-item">
<a href="">用户</a>
</li>
<li class="layui-nav-item">
<a href="javascript:;">其它系统</a>
<dl class="layui-nav-child">
<dd>
<a href="">邮件管理</a>
</dd>
<dd>
<a href="">消息管理</a>
</dd>
<dd>
<a href="">授权管理</a>
</dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<img src="" class="layui-nav-img"> admin
</a>
<dl class="layui-nav-child">
<dd>
<a href="">基本资料</a>
</dd>
<dd>
<a href="">安全设置</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="">退出</a>
</li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;">文章管理</a>
<dl class="layui-nav-child">
<dd class="layui-this">
<a href="javascript:;">文章信息</a>
</dd>
<dd >
<a href="javascript:;">文章评论</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">广告管理</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;">广告信息</a>
</dd>
<dd>
<a href="javascript:;">广告评论</a>
</dd>
</dl>
</li>
</ul>
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px;">
<table id="tb-article" lay-filter="tb-article"></table>
</div>
</div>
<!--编辑表单-->
<div class="layui-row" id="editArticle" style="display:none;">
<div class="layui-col-md10">
<form class="layui-form layui-from-pane" id="saveArticle" style="margin-top:20px">
<div class="layui-form-item">
<label class="layui-form-label">文章作者</label>
<div class="layui-input-block">
<input type="text" name="name" id="name" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<input type="hidden" name="id" id="id">
<div class="layui-form-item">
<label class="layui-form-label">文章标题</label>
<div class="layui-input-block">
<input type="text" name="title" id="title" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">文章类型</label>
<div class="layui-input-block">
<input type="text" name="type" id="type" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登入次数</label>
<div class="layui-input-block">
<input type="text" name="reader" id="reader" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">文章内容</label>
<div class="layui-input-block">
<input type="text" name="content" id="content" required lay-verify="required" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item" style="margin-top:40px" id="check">
<div class="layui-input-block">
<button class="layui-btn layui-btn-submit " lay-submit="" lay-filter="saveArticle">保存</button>
<!--<button type="reset" class="layui-btn layui-btn-primary">重置</button>-->
</div>
</div>
</form>
</div>
</div>
<script type="text/html" id="toolbarDemo">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" lay-event="add"><i class="layui-icon"></i>新增</button>
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="remove"><i class="layui-icon"></i>删除</button>
</div>
</script>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-sm" lay-event="edit"><i class="layui-icon"></i>修改</a>
</script>
<div class="layui-footer">
<!-- 底部固定区域 -->
© kaitao.com
</div>
</div>
<script src="js/jquery.js"></script>
<script src="layui/layui.all.js"></script>
<script>
var element, layer, table, form;
$(function() {
// 使用模块
layui.use(['element', 'layer', 'table', 'form'], function() {
element = layui.element;
layer = layui.layer;
table = layui.table;
form = layui.form;
});
//第一个实例
var userTable = table.render({
elem: '#tb-article',
height: 585,
url: 'http://localhost:8888/kaitao/list' ,//数据接口
page: true ,//开启分页
toolbar: '#toolbarDemo',
cols: [[
//表头
{type: 'checkbox', fixed: 'left'}
,{field:'id', title:'ID', 80, fixed: 'left', sort: true, totalRowText: '合计'}
,{field:'name', title:'文章作者', 150,}
,{field:'title', title:'文章标题', 260}
,{field:'type', title:'文章类型', 150}
,{field:'reader', title:'登入次数', 100, sort: true, totalRow: true}
,{field:'content', title:'文章内容', 500}
,{fixed: 'right', title:'操作', toolbar: '#barDemo', 150}
]]
});
//监听表单提交
// 修改
form.on('submit(saveArticle)', function(data) {
layer.alert(JSON.stringify(data.field));
$.ajax({
url: 'http://localhost:8888/kaitao/save',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(data.field),
success: function(result) {
if (result.code == 200) {
// layer.msg("修改成功!", {icon: 6});
setTimeout(function() {
layer.closeAll(); //关闭所有的弹出层
userTable.reload();
}, 300);
} else {
layer.msg("操作失败!", {
icon: 5
});
}
}
});
return false;
});
//工具栏事件
table.on('toolbar(tb-article)', function(obj) {
var checkStatus = table.checkStatus(obj.config.id);
var checkData = checkStatus.data;
var ids = [];
switch (obj.event) {
// 新增
case 'add':
$("#id").val('');
$("#name").val('');
$("#title").val('');
$("#type").val('');
$("#reader").val('');
$("#content").val('');
layer.open({
type: 1,
offset: '10px',
title: "新增文章",
area: ['500px', '450px'],
content: $("#editArticle")
});
break;
// 删除
case 'remove':
if (checkData.length == 0) {
layer.alert('请选择要操作的行');
} else {
layer.confirm('确定要删除吗?', function(index) {
for (var i = 0; i < checkData.length; i++) {
ids.push(checkData[i].id);
}
//layer.alert(JSON.stringify(ids));
$.ajax({
url: 'http://localhost:8888/kaitao/remove',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(ids),
success: function(result) {
if (result.code == 200) {
setTimeout(function() {
layer.closeAll(); //关闭所有的弹出层
userTable.reload();
}, 300);
}else {
layer.msg("操作失败!", {icon: 5});
}
}
});
});
}
break;
case 'getCheckData':
layer.alert(JSON.stringify(data));
break;
case 'getCheckLength':
var data = checkStatus.data;
layer.msg('选中了:' + data.length + ' 个');
break;
case 'isAll':
layer.msg(checkStatus.isAll ? '全选' : '未全选')
break;
};
});
// 监听工具条
table.on('tool(tb-article)', function(obj) {
var data = obj.data;
// 修改
if (obj.event === 'edit') {
$("#id").val(data.id);
$("#name").val(data.name);
$("#title").val(data.title);
$("#type").val(data.type);
$("#reader").val(data.reader);
$("#content").val(data.content);
layer.open({
type: 1,
offset: '10px',
title: "修改文章",
area: ['500px', '450px'],
content: $("#editArticle")
});
}
});
});
</script>
</body>
</html>
总结:过程中遇到的问题。
- 前后端分离,前后端用JSON交互,所以要写一个工具类,用来放“code,msg,count,data”,方便后端传JSON数据给前端。
- 要配置全局跨域,否者前端拿不到后端数据
- 要写一个批量删除,所以自己在repository写了一个sql语句
- 用的layui框架,要遵循layui的规则,前端页面复制前记得导入layui静态文件
- 记得改yml数据库名称.用户和密码
有什么问题可以后台留言