B站演示视频完整代码 三连后私信我获取~
撸了一上午完成的SPA商品管理系统,求三连!
Maynor手把手教你完成一个SpringBoot+Vue+Element演示视频(最后出现了点小bug)_哔哩哔哩_bilibili
项目需求 商品管理系统 1、商品列表多条件查询包括模糊查询,区间查询,类别选择和品牌选择、列表分页、类别和品类下拉列表选择
2、添加商品 3、修改商品 4、批量删除 5、单个商品删除 项目搭建:SpringBoot项目的搭建(你的第一个SpringBoot项目)_A Coder-CSDN博客_springboot 项目
项目结构 后端结构 配置文件pom.xml
org.springframework.boot spring-boot-starter-parent2.5.5 UTF-8 UTF-8 1.8 1.3.2 2.0.2 5.1.32 1.2.5 1.1.10 1.18.16 org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-jdbcorg.mybatis.spring.boot mybatis-spring-boot-starter${mybatis.starter.version} tk.mybatis mapper-spring-boot-starter${mapper.starter.version} com.github.pagehelper pagehelper-spring-boot-starter${pageHelper.starter.version} mysql mysql-connector-java${mysql.version} com.alibaba druid-spring-boot-starter${durid.starter.version} org.projectlombok lombok${lombok.version} commons-lang commons-lang2.6 org.springframework.boot spring-boot-maven-plugin
application.properties
#Tomcat server.port=8090 #DB configuration spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test3?useUnicode=true&characterEncoding=utf8 spring.datasource.username=root spring.datasource.password=root #druid spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.druid.initial-size=1 spring.datasource.druid.min-idle=1 spring.datasource.druid.max-active=20 spring.datasource.druid.test-on-borrow=true spring.datasource.druid.stat-view-servlet.allow=true logging.level.com.czxy=debug封装类
baseResult
package com.czxy.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.ResponseEntity;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class baseResult {
private Integer code;
private String msg;
private Object data;
private Integer total;
public baseResult(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static ResponseEntity success(Object data){
return ResponseEntity.ok(new baseResult(10000,"成功",data));
}
public static ResponseEntity fail(){
return ResponseEntity.ok(new baseResult(10001,"失败",null));
}
public static ResponseEntity success(Object data,Integer total){
return ResponseEntity.ok(new baseResult(10000,"成功",data,total));
}
}
GlobalCorsConfig
package com.czxy.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlbasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//放行哪些原始域
config.addAllowedOrigin("*");
//是否发送cookie信息
config.setAllowCredentials(false);
//放行哪些原始域(请求方式)
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET"); //get
config.addAllowedMethod("PUT"); //put
config.addAllowedMethod("POST"); //post
config.addAllowedMethod("DELETe"); //delete
config.addAllowedMethod("PATCH");
config.addAllowedHeader("*");
//2.添加映射路径
UrlbasedCorsConfigurationSource configSource = new UrlbasedCorsConfigurationSource();
configSource.registerCorsConfiguration(";
;
;
;
;
;
;
;
;
;
--
-- Table structure for table `brand`
--
DROP TABLE IF EXISTS `brand`;
;
;
CREATE TABLE `brand` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
;
--
-- Dumping data for table `brand`
--
LOCK TABLES `brand` WRITE;
;
INSERT INTO `brand` VALUES (1,'花花公子'),(2,'唐狮'),(4,'太平鸟'),(5,'森马'),(6,'大嘴猴'),(7,'adidas'),(8,'耐克'),(9,'苹果'),(10,'华为'),(11,'小米'),(12,'格力');
;
UNLOCK TABLES;
--
-- Table structure for table `category`
--
DROP TABLE IF EXISTS `category`;
;
;
CREATE TABLE `category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
;
--
-- Dumping data for table `category`
--
LOCK TABLES `category` WRITE;
;
INSERT INTO `category` VALUES (1,'女装'),(2,'男装'),(3,'内衣'),(4,'家电'),(5,'吸尘器'),(6,'取暖器'),(7,'手机'),(8,'家纺');
;
UNLOCK TABLES;
--
-- Table structure for table `goods`
--
DROP TABLE IF EXISTS `goods`;
;
;
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`brand_id` int(11) DEFAULT NULL,
`category_id` int(11) DEFAULT NULL,
`introduction` varchar(50) DEFAULT NULL,
`store_num` int(11) DEFAULT NULL,
`price` double DEFAULT NULL,
`create_time` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
;
--
-- Dumping data for table `goods`
--
LOCK TABLES `goods` WRITE;
;
INSERT INTO `goods` VALUES (2,'华为Mate30',10,7,'华为MATE30 金色1T',200,9999,'2021-10-22'),(8,'运动鞋',8,1,'百搭潮休闲鞋子',6000,999,'2021-11-02'),(9,'夹克',4,2,'新款迷彩休闲连帽上衣',8888,789,'2021-11-01'),(10,'demo',NULL,NULL,'xxxx',1,999,'2021-11-03'),(11,'1',NULL,NULL,'1',111,11,NULL),(12,'2',NULL,NULL,NULL,222,22,'2021-11-25T16:00:00.000Z'),(13,'123',NULL,NULL,'123',12,123,'2021-11-09');
;
UNLOCK TABLES;
;
;
;
;
;
;
;
;
-- Dump completed on 2021-11-05 9:27:52
后端代码部分
主要完成 entity/dao/service/controller/vo的开发,由于代码重复仅贴出Goods的完整代码
entity层:
@Table(name = "goods")
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class TTeacher implements Serializable {
//id
// name
// brand_id
// category_id
// introduction
// store_num
// price
// create_time
@Id
private Integer id;
private String name;
private Integer brand_id;
private Integer category_id;
private String introduction;
private Integer store_num;
private Double price;
private String create_time;
// 在java的日期类型只要符合2012-02-02
private TSchool school;
private TType type;
}
dao层:
@org.apache.ibatis.annotations.Mapper public interface TeacherMapper extends Mapper{ }
service层:
public interface TeacherService {
ResponseEntity findByCondition(TeacherSearchVO teacherSearchVO);
boolean add(TTeacher tea);
TTeacher findById(Integer id);
boolean update(TTeacher tea);
boolean deleteById(Integer id);
List selectAll();
}
impl 实现类
@Service
@Transactional
public class TeacherServiceImpl implements TeacherService {
@Autowired
private TeacherMapper teacherMapper;
@Autowired
private SchoolMapper schoolMapper;
@Autowired
private TypeMapper typeMapper;
@Override
public ResponseEntity findByCondition(TeacherSearchVO teacherSearchVO) {
// List teaList = new ArrayList<>();//最终要返回到前端的数据
//拼接条件
String teacherName = teacherSearchVO.getTeacherName();
Integer schoolId = teacherSearchVO.getSchoolId();
Integer typeId = teacherSearchVO.getTypeId();
String typeName = teacherSearchVO.getTypeName();
Integer minSalary = teacherSearchVO.getMinSalary();
Integer maxSalary = teacherSearchVO.getMaxSalary();
Integer page = teacherSearchVO.getPage();
Integer rows = teacherSearchVO.getRows();
Example example = new Example(TTeacher.class);
Example.Criteria criteria = example.createCriteria();
//1 名字模糊
if (StringUtils.isNotBlank(teacherName)){
criteria.andLike("name","%"+teacherName+"%");
}
//2 id精确匹配
if (schoolId!=null&&StringUtils.isNotBlank(schoolId.toString())){
criteria.andEqualTo("brand_id",schoolId);
}
if (typeId!=null&&StringUtils.isNotBlank(typeId.toString())){
criteria.andEqualTo("category_id",typeId);
}
if (minSalary!=null&&StringUtils.isNotBlank(minSalary.toString())){
criteria.andGreaterThanOrEqualTo("price",minSalary);
}
//4
if (maxSalary!=null&&StringUtils.isNotBlank(maxSalary.toString())){
criteria.andLessThanOrEqualTo("price",maxSalary);
}
//查找总条数,供分页使用
int total = teacherMapper.selectByExample(example).size();
//7 后端分页
PageHelper.startPage(page,rows);
//8 查出结果
List teacherList = teacherMapper.selectByExample(example);
//后端关联id显示名字
for (TTeacher tea:teacherList){
tea.setType(typeMapper.selectByPrimaryKey(tea.getCategory_id()));
tea.setSchool(schoolMapper.selectByPrimaryKey(tea.getBrand_id()));
}
if (teacherList.size()==0&&teacherSearchVO.getPage()!=1){
page = total%rows==0?total/rows:(total/rows+1);
teacherSearchVO.setPage(page);
findByCondition(teacherSearchVO);
}
return baseResult.success(teacherList,total);
}
@Override
public boolean add(TTeacher tea) {
return teacherMapper.insert(tea)==1;
}
@Override
public TTeacher findById(Integer id) {
return teacherMapper.selectByPrimaryKey(id);
}
@Override
public boolean update(TTeacher tea) {
return teacherMapper.updateByPrimaryKey(tea)==1;
}
@Override
public boolean deleteById(Integer id) {
return teacherMapper.deleteByPrimaryKey(id)==1;
}
@Override
public List selectAll() {
return teacherMapper.selectAll();
}
}
VO类:
@Data
public class TeacherSearchVO {
private String teacherName;
private String typeName;
private Integer schoolId;
private Integer typeId;
private Integer minSalary;
private Integer maxSalary;
private Integer page;//页码
private Integer rows;//行数
}
controller层:
@RestController
@RequestMapping("/teacher")
public class TeacherController {
@Autowired
private TeacherServiceImpl teacherService;
@GetMapping("/condition")
public ResponseEntity findByCondition(TeacherSearchVO teacherSearchVO){
ResponseEntity rbr = teacherService.findByCondition(teacherSearchVO);
return rbr;
}
@GetMapping("/all")
public List selectAll( ){
List rbr = teacherService.selectAll();
return rbr;
}
@PostMapping
public ResponseEntity add(@RequestBody TTeacher tea){
boolean flag = teacherService.add(tea);
if (flag){
return baseResult.success("新增成功");
}else{
return baseResult.fail();
}
}
@GetMapping("/{id}")
public ResponseEntity findById(@PathVariable("id") Integer id){
TTeacher tea = teacherService.findById(id);
return baseResult.success(tea);
}
@PutMapping
public ResponseEntity update(@RequestBody TTeacher tea){
boolean flag = teacherService.update(tea);
if (flag){
return baseResult.success("修改成功");
}else{
return baseResult.fail();
}
}
@DeleteMapping("/{id}")
public ResponseEntity deleteById(@PathVariable Integer id){
boolean flag= teacherService.deleteById(id);
if (flag){
return baseResult.success("删除成功");
}else{
return baseResult.fail();
}
}
@DeleteMapping("/batchDelete/{ids}")
public ResponseEntity bachDelete(@PathVariable String ids){
String[] splitIds = ids.split(",");
for (String id:splitIds){
teacherService.deleteById(Integer.parseInt(id));
}
return baseResult.success("删除成功");
}
}
Maynor小声bb:后端完成,接下来我们转战前端页面的实现!
前端代码部分: vue创建命令:npm create xxx cd xxx npm run servevue安装命令:
npm installelementui 安装
npm i element-ui -Smain.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import axios from 'axios'
axios.defaults.baseURL = "http://localhost:8090"
Vue.prototype.$http = axios
Vue.use(ElementUI)
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
App.vue
商品管理
index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/schoolList',
name: 'SchoolList',
component: () => import('@/views/SchoolList.vue')
},
{
path: '/teacherList',
name: 'TeacherList',
component: () => import('@/views/TeacherList.vue')
},
{
path: '/addTeacher',
name: 'AddTeacher',
component: () => import('@/views/AddTeacher.vue')
},
{
path: '/updateTeacher/:id(\d+)',
name: 'UpdateTeacher',
component: () => import('@/views/UpdateTeacher.vue')
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.base_URL,
routes
})
export default router
前端增删改查
页面显示
新增商品
品牌:
类别:
商品名称:
商品价格:-
| 全选 | 商品ID | 商品名称 | 商品品牌 | 商品类别 | 商品价格 | 商品库存 | 发布时间 | 商品介绍 | 操作 |
|---|---|---|---|---|---|---|---|---|---|
| {{tea.id}} | {{tea.name}} | {{tea.school.name}} | {{tea.type.name}} | {{tea.price}} | {{tea.store_num}} | {{tea.create_time}} | {{tea.introduction}} |
js
export default {
data() {
return {
id:[],
teacherSearchVo:{
page:1,
rows:3,
schoolId:"",
typeId:""
},
teaList:[],//商品列表
schoolList:[],//所有的学校集合
categoryList:[],//所有的类别集合
total:0,//总条数
dels:[],//批量删除的id集合
selectAll:false,//true全选 false全不选
}
},
methods: {
async initTeaList(){
let res = await this.$http.get("/teacher/condition",{params:this.teacherSearchVo})
console.log(res)
this.teaList = res.data.data
this.total = res.data.total
},
async initSchoolList(){
let res = await this.$http.get("/school/all")
this.schoolList = res.data.data
},
async initCategoryList(){
let res = await this.$http.get("/type/all")
this.categoryList = res.data.data
console.log(this.categoryList)
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.teacherSearchVo.rows = val
this.initTeaList()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.teacherSearchVo.page = val
this.initTeaList()
},
async deleteById(id){
console.log(id)
let res = await this.$http.delete("/teacher/"+id)
if(res.data.code==10000){
alert("删除成功")
this.initTeaList()
}else{
alert("删除失败")
}
},
async batchDelete(){
// 组装id
let delIds = "";
for(let i=0;i
添加功能
新增商品
通过点击添加按钮跳转到添加的页面
新增商品
商品名字:
商品品牌:
商品类别:
商品介绍:
商品价格:
商品库存:
发布时间:
修改功能
修改
与添加页面类似,仅需修改js即可
export default {
data() {
return {
teacherSearchVo:{
page:1,
rows:3,
schoolId:"",
typeId:""
},
teacher:{
sex:"",
typeId:"",//默认:--请选择--
},//商品是一个对象
typeList:[],//商品类型数组
schoolList:[],//所有的学校集合
}
},
methods: {
async initTeacher(){
let res = await this.$http.get("/teacher/"+this.id)
// debugger
this.teacher = res.data.data
},
//初始化商品类型的方法
async initTypeList(){
let res = await this.$http.get("/type/all")
this.typeList = res.data.data
},
async update(){
let res = await this.$http.put("/teacher",this.teacher)
if(res.data.code==10000){
alert("修改成功")
this.$router.push("/teacherList")
}else{
alert("修改失败")
}
},
async initSchoolList(){
let res = await this.$http.get("/school/all")
this.schoolList = res.data.data
},
},
created() {
this.id = this.$route.params.id
this.initTeacher()
this.initTypeList()
this.initSchoolList()
},
}
删除功能
删除
async deleteById(id){
console.log(id)
let res = await this.$http.delete("/teacher/"+id)
if(res.data.code==10000){
alert("删除成功")
this.initTeaList()
}else{
alert("删除失败")
}
},
目前功能基本实现了!我们再来完善一下
批量删除
功能分析:
实现批量删除的办法其实有很多,我这里是把批量传入的id放进数组里,然后后端用for循环遍历删除。
js
async batchDelete(){
// 组装id
let delIds = "";
for(let i=0;i
模糊查询 多条件查询
思考一下该怎么写,代码在上面已贴出
Elementui 实现分页查询
使用npm 安装完ui插件后,改下官网模板
参数解释:
@size-change:每页条数通过下拉列表框发生改变
@current-change:当前页码发生改变
current-page:当前是第几页 2
page-sizes:下拉列表框,设置每页显示条数
page-size:每页显示条数 3
total:该数据在数据库里的总条数 16,作用:计算总页数
js
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.teacherSearchVo.rows = val
this.initTeaList()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.teacherSearchVo.page = val
this.initTeaList()
},
后记
博客主页:manor的博客_小小manor_CSDN博客-Java,全栈,大数据领域博主
欢迎点赞 收藏 ⭐留言 如有错误敬请指正!
本文由 manor 原创,首发于 CSDN博客



