学习链接
模块创建
实体类快速开发(lombok)
数据层标准开发(基础CRUD)
开启MP运行日志
分页
数据层标准开发(条件查询)
业务层标准开发(基础CRUD)
业务层快速开发(基于MyBatisPlus构建)
表现层标准开发
表现层数据一致性处理(R对象)
前后端调用(axios发送异步请求)
列表功能
添加功能
删除功能
修改功能(加载数据)
修改功能
异常消息处理
分页
分页功能维护(删除BUG)
条件查询
完结
模块创建:
勾选SpringMVC与MYSQL坐标
(手动添加Mybatis Plus和Druid的坐标)
修改配置文件为yml格式
设置服务器端口8080
1.勾选SpringMVC与MYSQL坐标
(手动添加Mybatis Plus和Druid的坐标)
2.修改配置文件为yml格式
3.设置服务器端口8080
```xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
2.实体类快速开发
利用lombok进行实体类快速开发。
lombok:一个java类库,提供一组注解用于简化POJO实体类开发
1.导入lombok坐标,版本号由SpringBoot提供,故无需指定
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
2.@Data注解
//@Data代表了@Getter,@Setter等,包含有get,set,toString,hashCode,equals等方法
//@AllArgsConstructor // 有参构造
//@NoArgsConstructor // 无参构造
//实体类一般无参构造,而类默认有无参构造器,
@Data
public class Brand {
private int id;
private String brand_name;
private String company_name;
private int ordered;
private String description;
private int status;
}
补:查看实体类含有的方法;Alt+7
可以看出lombok的@Data帮助快速实现了get(),set(),toString(),hashCode()方法
补充:如果测试发现toString()方法打印String类型的数据是null,我这里原因是数据库和实体类里该变量名中有_,命名不用_即可。
如:brand_name 改为brandname
1.druid和Mybatisplus第三方技术坐标添加,
2.配置数据源与MybatisPlus对应配置
3.开发数据层Dao接口(继承BaseMapper,泛型是实体类)
4.制作测试类测试Dao功能是否有效
整合的druid的数据源配置方式:
server:
port: 8080
#配置数据库链接和druid
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db
username: root
password: 1234
#挂上表名前缀
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
数据层dao.BrandDao创建
package com.tsdusl.dao;
import com.tsdusl.domain.Brand;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface BrandDao {
//Mybatis格式,Mybatis plus可以快速实现
@Select("select * from tb_brand where id = #{id}")
public Brand getById(Integer id);
}
测试dao.BrandDaoTestCase
package com.tsdusl.dao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class BrandDaoTestCase {
@Autowired
private BrandDao brandDao;
@Test
void testgetById() {
System.out.println(brandDao.getById(1));
}
}
数据层dao.BrandDao用Mybatis plus实现
只需要将该数据层接口继承BaseMapper,且泛型写我们要处理的实体类名即可
package com.tsdusl.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tsdusl.domain.Brand;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BrandDao extends BaseMapper<Brand> {
//指定泛型Brand,使之数据层DAO知道自己对哪个实体类 *** 作
}
Ctrl+F12查看当前接口继承的方法
数据库的id自增需要在yml文件中添加配置
#挂上表名前缀
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
id-type: auto
测试:
package com.tsdusl.dao;
import com.tsdusl.domain.Brand;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class BrandDaoTestCase {
@Autowired
private BrandDao brandDao;
@Test
void testselectById() {
System.out.println(brandDao.selectById(1));
}
@Test
void testSave(){
Brand brand = new Brand();
brand.setBrandname("lgt");
brand.setCompanyname("nuaa");
brand.setOrdered(1111);
brand.setDescription("冲啊java");
brand.setStatus(1);
brandDao.insert(brand);
}
@Test
void testUpdate(){
Brand brand = new Brand();
brand.setId(1);
brand.setBrandname("lgt");
brand.setCompanyname("nuaa");
brand.setOrdered(1111);
brand.setDescription("冲啊java");
brand.setStatus(1);
brandDao.updateById(brand);
}
@Test
void testDelete(){
brandDao.deleteById(49);
brandDao.deleteById(50);
brandDao.deleteById(51);
brandDao.deleteById(52);
brandDao.deleteById(53);
brandDao.deleteById(54);
brandDao.deleteById(1);
}
@Test
void testGetALl(){
System.out.println(brandDao.selectList(null));
//这里是条件选择,设置为null则为没有条件限制,全部选择
}
}
4.开启MP运行日志
添加日志配置
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
id-type: auto
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志选择配置
如此以来,可在控制台实现MP对数据库进行的详细 *** 作,那么test时也就不用输出了,只需要调用DAO的方法,具体对数据库 *** 作的细节会由日志在控制台打出。开发测试的时候启用日志,上线服务器的时候不能开启,否则服务器难以承受。
5.分页MP虽然实现了分页功能,但是使用与否需要自行设置;使用的话需要添加拦截器,拦截器通过配置文件添加,该配置文件要在Application文件所在包下才能被扫描到
添加config包和类;
package com.tsdusl.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration将其设置成配置类,使之配置信息能够被读取到
@Configuration
public class MPConfig {
//不论做什么,本质还是spring,即都得受spring管理,而spring是管理bean的
//使用Spring管理第三方bean的方式将bean初始化出来并将其加载给spring环境
//第三方Bean的配置方式@Bean
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//定义MP拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//创建拦截器的壳
//添加具体拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());//向拦截器壳内添加page拦截器
return interceptor;
}
//这里主要是创建了一个bean交给Spring,这个Bean是一个MybatisPlus的拦截器,具体拦截器是Page拦截器
}
分页测试,selectPage返回的是Ipage,其中封装了所有与page相关的数据
@Test
void testGetPage(){
IPage page = new Page(1,5);
brandDao.selectPage(page,null);
// System.out.println(page.getCurrent());
// System.out.println(page.getSize());
// System.out.println(page.getTotal());
// System.out.println(page.getPages());
// System.out.println(page.getRecords());
}
分页 *** 作是在MybatisPlus的常规 *** 作基础上增强得到,内部是动态的拼写SQL语句,因此需要增强其对应功能,使用MybatisPlus拦截器实现
6.数据层标准开发(条件查询) @Test
void testGetBy(){
//queryWrapper就是查询条件
//创建对象,泛型是实体类名
QueryWrapper<Brand> qw = new QueryWrapper<>();
//添加条件,属性名写错的话会运行出错
qw.like("brandname","华");
brandDao.selectList(qw);
}
@Test
void test2GetBy(){
String s_brandname = "null";
QueryWrapper<Brand> lqw = new QueryWrapper<>();
lqw.like(s_brandname != null,Brand::getBrandname, s_brandname);
brandDao.selectList(lqw);
}
7.业务层标准开发(基础CRUD)
数据层直接 *** 作数据库
业务层进行实际业务的 *** 作,复合调用数据层接口方法
创建业务接口及其实现类:
业务层接口创建:
package com.tsdusl.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tsdusl.domain.Brand;
import java.util.List;
public interface BrandService {
Boolean save(Brand brand);
Boolean update(Brand brand);
Boolean deleteById(Integer id);
Brand getById(Integer id);
List<Brand> getAll();
IPage<Brand> getPage(int currentPage,int pagesize);
}
业务层实现类创建:
要@Service将其定义为业务层对应的Bean
package com.tsdusl.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tsdusl.dao.BrandDao;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.BrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service //定义为业务层对应的bean
public class BrandServiceimpl implements BrandService {
@Autowired
private BrandDao brandDao;
@Override
public Boolean save(Brand brand) {
return brandDao.insert(brand) > 0;
//可以看到数据层的函数是针对数据库直接 *** 作的,是影响数据库行的
//insert返回int行数,故 > 0 表示添加成功
}
@Override
public Boolean update(Brand brand) {
return brandDao.updateById(brand) > 0;
}
@Override
public Boolean deleteById(Integer id) {
return brandDao.deleteById(id) > 0;
}
@Override
public Brand getById(Integer id) {
return brandDao.selectById(id);
}
@Override
public List<Brand> getAll() {
return brandDao.selectList(null);
}
@Override
public IPage<Brand> getPage(int currentPage,int pagesize) {
IPage page = new Page(currentPage,pagesize);
return brandDao.selectPage(page,null);
}
}
测试类:
package com.tsdusl.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tsdusl.domain.Brand;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class BrandServiceTestCase {
//注入业务层对象
@Autowired
private BrandService brandService;
@Test
void testgetById(){
System.out.println(brandService.getById(4));;
}
@Test
void testSave(){
Brand brand = new Brand();
brand.setBrandname("lgt");
brand.setCompanyname("nuaa");
brand.setOrdered(1111);
brand.setDescription("冲啊java");
brand.setStatus(1);
brandService.save(brand);
}
@Test
void testUpdate(){
Brand brand = new Brand();
brand.setId(1);
brand.setBrandname("lgt");
brand.setCompanyname("nuaa");
brand.setOrdered(1111);
brand.setDescription("冲啊java");
brand.setStatus(1);
brandService.update(brand);
}
@Test
void testDelete(){
brandService.deleteById(55);
}
@Test
void testGetALl(){
System.out.println(brandService.getAll());;
//这里是条件选择,设置为null则为没有条件限制,全部选择
}
@Test
void testgetPage(){
IPage page = brandService.getPage(1,5);
System.out.println(page.getCurrent());
System.out.println(page.getSize());
System.out.println(page.getTotal());
System.out.println(page.getPages());
System.out.println(page.getRecords());
}
}
8.业务层快速开发(基于MyBatisPlus构建)
使用MyBatisPlus提供的业务层通用接口IService<实体类>和ServiceImpl<数据层接口,实体类>
service接口:
package com.tsdusl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.tsdusl.domain.Brand;
public interface IBrandService extends IService<Brand> {
}
实现类:
package com.tsdusl.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsdusl.dao.BrandDao;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.IBrandService;
import org.springframework.stereotype.Service;
@Service
public class BrandServiceImpl extends ServiceImpl<BrandDao, Brand> implements IBrandService {
}
9.表现层标准开发
基于Restful进行表现层接口开发
使用Postman测试表现层接口功能
区分不同请求所对应的表现层方法:
信号区分:
get查询
post添加
put修改
delete删除
数据传输方式区分:
@RequestBody:通过请求体传输的JSON数据
@PathVariable ,(“/{id}”)通过路径参数传参
controller包下的BrandController.java:
package com.tsdusl.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.IBrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/brands")
public class BrandController {
@Autowired // 自动装配
private IBrandService brandService;
@GetMapping //定义该请求为get信号
public List<Brand> getAll(){
return brandService.list();
}
@PostMapping
public Boolean save(@RequestBody Brand brand){
return brandService.save(brand);
}
//保存和修改一般用 @RequestBody表示接收的数据是通过请求体传输的JSON数据
@PutMapping
public Boolean update(@RequestBody Brand brand){
return brandService.updateById(brand);
}
@DeleteMapping("/{id}")
public Boolean delete(@PathVariable Integer id){
return brandService.removeById(id);
}
//删除和获取单个,一般是使用路径变量来传参("{id}")
//例如://localhost:8080/books/2
@GetMapping("/{id}")
public Brand getById(@PathVariable Integer id){
return brandService.getById(id);
}
@GetMapping("/{currentPage}/{pageSize}")
public IPage<Brand> getPage(@PathVariable int currentPage,@PathVariable int pageSize){
return brandService.getPage(currentPage,pageSize);
}
}
业务端接口新增自己创建的分页方法:
IPage<Brand> getPage(int currentPage,int pageSize);
10.表现层数据一致性处理(R对象)
表现层数据返回给前端使用
封装到data中,以便前端取数据
设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议
R类:
package com.tsdusl.controller.utils;
import lombok.Data;
@Data
public class R {
private Boolean flag;
private Object data;
public R() {
}
public R(Boolean flag, Object data) {
this.flag = flag;
this.data = data;
}
public R(Boolean flag) {
this.flag = flag;
}
}
controller.BrandController返回值修改为R类型:
package com.tsdusl.controller;
import com.tsdusl.controller.utils.R;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.IBrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/brands")
public class BrandController {
@Autowired // 自动装配
private IBrandService brandService;
@GetMapping //定义该请求为get信号
public R getAll(){
return new R(true, brandService.list());
}
@PostMapping
public R save(@RequestBody Brand brand){
return new R(brandService.save(brand));
}
//保存和修改一般用 @RequestBody表示接收的数据是通过请求体传输的JSON数据
@PutMapping
public R update(@RequestBody Brand brand){
return new R(brandService.updateById(brand));
}
@DeleteMapping("/{id}")
public R delete(@PathVariable Integer id){
return new R(brandService.removeById(id));
}
//删除和获取单个,一般是使用路径变量来传参("{id}")
//例如://localhost:8080/books/2
@GetMapping("/{id}")
public R getById(@PathVariable Integer id){
return new R(true,brandService.getById(id));
}
@GetMapping("/{currentPage}/{pageSize}")
public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
return new R(true,brandService.getPage(currentPage,pageSize));
}
}
11.前后端调用(axios发送异步请求)
钩子函数是用来完成页面加载时的部分数据初始化工作
这里利用钩子函数调用methods中的getAll(),然后发送axios异步请求访问/brands资源,得到返回数据res,我们记得之前后端表现层设计时,返回的是R类型,那么.data即可获取其数据。
//钩子函数,VUE对象初始化完成后自动执行
created() {
//调用查询全部数据的 *** 作
this.getAll();
},
methods: {
//列表
getAll() {
console.log("run getAll()...")
//发送异步请求axios
axios.get("/brands").then((res)=>{
console.log(res.data);
})
},
这些静态资源放在resources.static包下:
12.列表功能这里设:
methods: {
//列表
getAll() {
// console.log("run getAll()...")
//发送异步请求axios
axios.get("/brands").then((res)=>{
// console.log(res.data);
this.dataList = res.data.data;
})
},
13.添加功能
这里设置的d窗表格添加,几个与按钮绑定的函数如下:
//d出添加窗口
handleCreate() {
this.dialogFormVisible = true;
this.resetForm();//用于每次打开表单时,清楚其上次的数据信息
},
//重置表单,用于每次打开表单时,清楚其上次的数据信息
resetForm() {
this.formData = {};
},
//添加
handleAdd () {
//发送请求时要把数据发送过去,即formdata
axios.post("/brands",this.formData).then((res)=>{
// console.log(res.data);
//判断当前 *** 作是否成功
if(res.data.flag){
//关闭d层,重新加载数据
this.dialogFormVisible = false;
this.$message.success("添加成功");//用于提醒用户 *** 作成功与否
}else{
this.$message.error("添加失败");
}
}).finally(()=>{
this.getAll();//不管成功与否,都要加载所有数据,所以用finally做最后 *** 作
})
},
//取消
cancel(){
this.dialogFormVisible = false;
this.$message.info("当前 *** 作取消");
},
14.删除功能
界面编辑的删除处scope概念:
<template slot-scope="scope">
<!-- element-ui将数据封装成scope行对象,scope.row表示该行数据-->
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
</template>
15.修改功能(加载数据)
通过传递当前行数据的id到后台查询;
利用前端数据双向绑定将查询到的数据进行回显;
//d出编辑窗口//查询数据进行回显
handleUpdate(row) {
axios.get("/brands/" + row.id).then((res)=>{
if(res.data.flag && res.data.data != null){
// this.$message.success("删除成功");//用于提醒用户 *** 作成功与否
this.formData = res.data.data;
this.dialogFormVisible4Edit = true;
}else{
this.$message.error("数据同步异常, *** 作失败");
}
})
},
16.修改功能
//修改
handleEdit() {
axios.put("/brands",this.formData).then((res)=>{
//判断当前 *** 作是否成功
if(res.data.flag){
//关闭d层,重新加载数据
this.dialogFormVisible4Edit = false;
this.$message.success("修改成功");//用于提醒用户 *** 作成功与否
}else{
this.$message.error("修改失败");
}
}).finally(()=>{
this.getAll();//不管成功与否,都要加载所有数据,所以用finally做最后 *** 作
})
},
17.异常消息处理
表现层手动添加异常进行异常测试:
@PostMapping
public R save(@RequestBody Brand brand) throws IOException {
if(brand.getBrandname().equals("123")){
throw new IOException();//手动添加异常进行异常测试
}
return new R(brandService.save(brand));
}
SpringMVC中提供专用的异常处理器,通过该异常处理器可以进行异常处理。
SpringMvc属于Controller技术,所以在control.utils下创建类:
package com.tsdusl.controller.utils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//作为springmvc的异常处理器,至于业务层,数据层的异常,最终会抛到表现层
//@RestControllerAdvice:定义为Controller的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
//如下定义一个方法并添加注解@ExceptionHandler即可实现拦截所有异常信息
@ExceptionHandler
public R doException(Exception ex){
//记录日志,通知运维,开发
ex.printStackTrace();//控制台报异常
//前端处理,应该接收R类型数据,但是俩个成员变量不足,需补充成员变量
return new R(false,"服务器故障,稍后再试");
}
}
@Data
public class R {
private Boolean flag;
private Object data;
private String msg;
18.分页
使用el分页组件——定义分页组件绑定的数据模型——异步调用获取分页数据——进行分页数据回显。
前端分页组件:
<!--分页组件-->
<div class="pagination-container">
<!--handleCurrentChange控制换页-->
<!--控制当前页,页面大小,总数等-->
<el-pagination
class="pagiantion"
@current-change="exchangeCurrentChange"
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
layout="total, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
分页代码,注意分页返回的res.data.data中的records才是列表数据:
//列表//分页查询
getAll() {
// console.log("run getAll()...")
//发送异步请求axios
axios.get("/brands/" + this.pagination.currentPage + "/" + this.pagination.pageSize).then((res)=>{
// console.log(res.data);
this.pagination.currentPage = res.data.data.current;
this.pagination.pageSize = res.data.data.size;
this.pagination.total = res.data.data.total;
this.dataList = res.data.data.records;//这里分页查询后端返回的data是页面信息,其中包含列表数据以及页面格式
})
},
//切换页码
exchangeCurrentChange(currentPage) {
this.pagination.currentPage = currentPage;
this.getAll();
},
19.分页功能维护(删除BUG)
对查询结果进行校验,若当前页码值大于最大页码值,使用最大页码值作为当前页码值进行查询:
@GetMapping("/{currentPage}/{pageSize}")
public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
//判断当前查询页面是否大于实际有的页面,大于的话返回最后一页。
IPage<Brand> page = brandService.getPage(currentPage, pageSize);
if(page.getPages() < currentPage ){
page = brandService.getPage((int)page.getPages(), pageSize);
}
return new R(true,page);
}
20.条件查询
先将前端的输入框数据收集并绑定到创建的数据模型上,
因为条件查询也是查询之一,在分页查询之中,因此可在分页组件的数据模型中添加条件数据模型:
pagination: {//分页相关模型数据
currentPage: 1,//当前页码
pageSize:5,//每页显示的记录数
total:0,//总记录数
brandname: "",
companyname: "",
description: ""
}
<div class="box">
<div class="filter-container">
<el-input placeholder="品牌名称" v-model = pagination.brandname style="width: 200px;" class="filter-item"></el-input>
<el-input placeholder="公司名称" v-model = pagination.companyname style="width: 200px;" class="filter-item"></el-input>
<el-input placeholder="品牌描述" v-model = pagination.description style="width: 200px;" class="filter-item"></el-input>
<el-button @click="getAll()" class="dalfBut">查询</el-button>
<el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
条件传到后端后,需要在业务层接口与实现类进行新的getAll函数的重载:
从表现层getAll传到业务层,进行数据的处理:
@Override
public IPage<Brand> getPage(int currentPage, int pageSize, Brand brand) {
LambdaQueryWrapper<Brand> lqw = new LambdaQueryWrapper<>();
lqw.like(Strings.isNotEmpty(brand.getBrandname()),Brand::getBrandname,brand.getBrandname());
lqw.like(Strings.isNotEmpty(brand.getCompanyname()),Brand::getCompanyname,brand.getCompanyname());
lqw.like(Strings.isNotEmpty(brand.getDescription()),Brand::getDescription,brand.getDescription());
IPage<Brand> page = new Page(currentPage,pageSize);
brandDao.selectPage(page,lqw);
return page;
}
(我这里用的自己的数据库表,里面有排名,ordered初始值为0,查询又没有设置排名,导致界面无数据)
21.完结总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)