步骤一:注意使用idea创建springboot项目时必须在联网状态
步骤二:
步骤三:
结构如下:
在springBoot中,配置类config的包已经不需要了
注意书写格式,同级对齐,下一级比上一级多一个空格
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
password: root
username: root
url: jdbc:mysql://localhost:3306/db5?serverTimezone=GMT%2B8&useSSL=false
#修改tomcat的端口号
server:
port: 88
mybatis:
configuration:
map-underscore-to-camel-case: true
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 使用雪花算法自动填充id,当然MybatisPlus默认为雪花算法
id-type: assign_id
# 匹配表名和实体类名,这个表示表名为“tb_xxx"开头的,其中(xxx)和实体类名一样,@TableName也可以用来映射表名和实体类
# table-prefix: tb_
#配置全局逻辑删除,选定逻辑删除字段
# logic-delete-field: tbDeleted
# #确定逻辑删除后,表示逻辑删除的字段的用什么来表示改记录被删除
# logic-delete-value: 1
# #为被逻辑删除的字段应该怎样表示
# logic-not-delete-value: 0
同时给以下druid的依赖,虽然springBoot使用了maven的继承和依赖传递特性,但是并不是所有包都能继承,有些需要选配
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.6version>
dependency>
@Mapper:用来替代MybatisConfig中的包扫描配置
@Mapper//用来取代包扫描的动作
public interface UserDao {
@Insert("insert into users values(null,#{tbUsername},#{tbZhanghao},#{tbPassword},#{tbAge},#{tbGender},#{tbAddress},#{tbBirthday})")
public void save(Users user);
@Update("update users set tb_username=#{tbUsername},tb_zhanghao=#{tbZhanghao},tb_password=#{tbPassword},tb_age=#{tbAge},tb_gender=#{tbGender},tb_address=#{tbAddress},tb_birthday=#{tbBirthday} where tb_uid=#{tbUid} ")
public void update(Users user);
@Delete("delete from users where tb_uid=#{tbUid}")
public void delete(Integer id);
@Select("select * from users where tb_uid=#{tbUid}")
public Users selectById(Integer id);
@Select("select * from users")
public List<Users> selectAll();
/*
* 手写,分页查询
* */
@Select("select * from users limit #{start},#{pageSize}")
public List<Users> findByPage(@Param("start") int start, @Param("pageSize") int pageSize);
// 查询总的数据数量
@Select("select count(*) from users")
public int totalPage();
}
如果想要启动,就在启动类中开始就行,上面有标注启动类在哪里。但是我们这个没有当初选择时没有选Mybatis,所以应该不行,
后面我会改成使用MybatisPlus。
启动类,这些都是SpringBoot自动创建的:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Day07SpringBootApplication {
//被这个主类扫描的包需要放在和这个类同级的目录下
public static void main(String[] args) {
SpringApplication.run(Day07SpringBootApplication.class, args);
}
}
在Maven中添加依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
1.无侵入:只做增强不做改变,对现有工程不会产生影响,可以与mybatis配合使用
2.强大的CRUD操作:内置通用的Mapper,少量配置后即可完成基础的CRUD操作
3.支持Lambda:编写条件查询无需担心字段写错
4.支持主键自动生成
5.内置分页插件
id的主键生成策略:
MybatisPlus的分页插件需要配合到spring的拦截器一起使用。所以先编写配置类:
MybatisPlusConfig.java:
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
public class MybatisplusConfig {
@Bean
public MybatisPlusInterceptor setMpInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
@Override
public IPage<Users> findByPage(long currentPage, long pageSize) {
IPage<Users> Page = new Page<Users>(currentPage,pageSize);
IPage<Users> iPage = userDao.selectPage(Page,null);
return iPage;
}
@GetMapping("/{currentPage}/{pageSize}")
public Result selectByPage(@PathVariable long currentPage, @PathVariable long pageSize) {
IPage<Users> usersList = userService.findByPage(currentPage, pageSize);
Result result = new Result(usersList,Code.SELECT_OK,"");
return result;
}
为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中。
所以我们要在数据库中添加一个表示逻辑删除的字段,并且设置默认值。
// 这是一个用来标注逻辑删除的字段,用来表示用户是否被删除,在数据库中代表逻辑删除的字段应该有默认值
// 如果不想写@TableFiled与表中字段进行映射,就写与表中字段名称一样,我是因为开启了驼峰命名,否则也需要映射
// value代表未被逻辑删除,delval代表已被逻辑删除
// 该注解会在mp执行删除语句时更改(update语句)数据库中的字段数据,如果是执行其他的查询操作,则会在sql中填充where条件查询,如果为tb_Deleted=1则不对该数据进行查询
@TableLogic(value = "0",delval = "1")
private Integer tbDeleted;
使用了MybatisPlus就可使用其内置的Mapper,所以在数据层的注解可以注释掉了,但是@Mapper注解不能去掉,还需要继承BaseMapper<>
UserDao:
import cn.itheima.pojo.Users;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper//用来取代包扫描的动作,BaseMapper中的范型,其实是MybatisPlus用来执行sql语句时查询的表名,所以务必保证:类名与表名一直或者使用了@TableName映射,否则你查不出来的
public interface UserDao extends BaseMapper<Users> {
}
实体类的变化有点大,@Data需要lombok依赖,除了构造方法没有帮忙创建,其余都有。注意,我们需要保证实体类Users的名字和数据库中表的名字一致,否则就需要用@TableName(表名)映射一下,其他注意事项在代码注解中。也处理了后端向前端发送Long型数据,前端数据溢出的问题,使用了@JsonSerialize(using= ToStringSerializer.class)注解。id的数据类型应该为Long,数据库对应修改为bigint
Users:
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import org.springframework.stereotype.Repository;
import javax.annotation.sql.DataSourceDefinition;
import java.util.Date;
@Repository
@Data
public class Users {
// 注意:如果为设置id生成策略,但是数据库的主键设置为自增,则mybatisPlus会自动产生id生成测略,并且使用的雪花算法生成的
// 所以id的类型需要改为Long型并且,数据库中id字段的类型改为bigint
// 使用MybatisPlus则主键字段的名称必为“id”,数据库中的主键字段也为“id”。
// 使用JsonSerialize注解,后端数据在序列化时就可以转成字符串类型,解决了前端无法解析long型数据
@JsonSerialize(using= ToStringSerializer.class)
private Long id;
//我开启了驼峰命名表结构是tb_xxx所以可以映射,如果你的表中字段名和类中的属性名不一致且无法完成驼峰命名,请使用@TableFiled()映射一下
private String tbUsername;
private String tbZhanghao;
private Integer tbPassword;
private Integer tbAge;
private String tbGender;
private String tbAddress;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date tbBirthday;
// 这是一个用来标注逻辑删除的字段,用来表示用户是否被删除,在数据库中代表逻辑删除的字段应该有默认值
// 如果不想写@TableFiled与表中字段进行映射,就写与表中字段名称一样,我是因为开启了驼峰命名,否则也需要映射
// value代表未被逻辑删除,delval代表已被逻辑删除
// 该注解会在mp执行删除语句时更改(update)数据库中的字段数据,如果是执行其他的查询操作,则会在sql中填where条件查询,如果为1则不对该数据进行查询
// 可以全局配置也可以单独配置,看自己需求,全局配置就在“.yml”配置文件中配置即可
// jackson提供的注解
@TableLogic(value = "0",delval = "1")
private Integer tbDeleted;
public Users() {
}
public Users(Long id, String tbUsername, String tbZhanghao, Integer tbPassword, Integer tbAge, String tbGender, String tbAddress, Date tbBirthday, Integer tbDeleted) {
this.id = id;
this.tbUsername = tbUsername;
this.tbZhanghao = tbZhanghao;
this.tbPassword = tbPassword;
this.tbAge = tbAge;
this.tbGender = tbGender;
this.tbAddress = tbAddress;
this.tbBirthday = tbBirthday;
this.tbDeleted = tbDeleted;
}
}
这里方前端的全部,里面有修改的地方:
user.html(findByPage方法被修改了,以及按钮的传递参数名字被修改了):
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户管理title>
head>
<body>
<div id="userContains">
<table border="1px" cellspacing="0px" width="100%">
<tr>
<th>编号th>
<th>名称th>
<th>账号th>
<th>密码th>
<th>年龄th>
<th>性别th>
<th>住址th>
<th>生日th>
<th>操作th>
tr>
<tr v-for="(user,i) in users">
<td>{{i+1}}td>
<td>{{user.tbUsername}}td>
<td>{{user.tbZhanghao}}td>
<td>{{user.tbPassword}}td>
<td>{{user.tbAge}}td>
<td v-if="user.tbGender=='0'">男td>
<td v-if="user.tbGender=='1'">女td>
<td>{{user.tbAddress}}td>
<td>{{user.tbBirthday}}td>
<td><a href="#" @click="updateUser(user.id)">编辑a> |<a href="#" @click="deleteUser(user.id)">删除a>td>
tr>
table>
<div>
<a href="" @click.prevent="changePage(page)" v-for="page in pageDate.totalPage">{{page}} a>
div><br>
<div>
<a href="/pages/addUser.html">添加用户a>
div>
div>
<script src="../js/vue.js">script>
<script src="../js/axios-0.18.0.js">script>
<script>
new Vue({
el: "#userContains",
data() {
return {
users:[],
pageDate:{
currentPage:1.0,
pageSize:2.0,
totalPage:0,
total:0,
}
}
},
methods: {
findAll() {
var _this = this
axios({
method: "get",
url: "/users",
}).then(function (resp) {
_this.users = resp.data.data
})
},
findByPage(){
var _this = this
// 分页助手版,分页查询
/*axios({
method: "get",
url: "/day05_SSM/users/"+_this.pageDate.currentPage+"/"+_this.pageDate.pageSize,
}).then(function (resp) {
console.log(resp.data.data);
_this.users = resp.data.data.list
_this.pageDate.total = resp.data.data.total
_this.pageDate.totalPage = resp.data.data.pages
})*/
axios({
method:"get",
url: "/users/"+_this.pageDate.currentPage+"/"+_this.pageDate.pageSize,
}).then(function (resp){
console.log(resp.data.data)
_this.users = resp.data.data.records
_this.pageDate.totalPage = resp.data.data.pages
})
},
changePage(currentPage){
this.pageDate.currentPage = currentPage;
this.findByPage();
},
deleteUser(uid){
_this1 = this
alert("点击删除"+uid)
axios({
method:"delete",
url:"/users/"+uid
}).then(function (resp){
alert( resp.data.msg)
_this1.findByPage();
})
},
updateUser(uid){
location.href="/pages/updateUser.html?id="+uid;
}
},
mounted() {
//this.findAll();
this.findByPage();
}
})
script>
<script>
script>
body>
html>
updateUser.html(只需注意实体类中tbUid字段已经被修改成id了,所以取的参数也改了):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="updateContains">
<form id="form" action="" method="post">
<input type="hidden" id="uid" v-model="user.id">
用户名:<input type="text" id="username" v-model="user.tbUsername"><br>
账号:<input type="text" id="zhanghao" v-model="user.tbZhanghao"><br>
密码:<input type="password" id="password" v-model="user.tbPassword"><br>
性别:<input type="radio" value="0" v-model="user.tbGender">男
<input type="radio" value="1" v-model="user.tbGender">女
<br>
地址:<input type="text" id="address" v-model="user.tbAddress"><br>
年龄:<input type="text" id="age" v-model="user.tbAge"><br>
生日:<input type="date" id="birthday" v-model="user.tbBirthday"><br>
<button type="button" id="bt" value="bt" @click="updateuser()">修改</button>
</form>
</div>
<script src="../js/vue.js"></script>
<script src="../js/axios-0.18.0.js"></script>
<script>
C1 = window.location.href.split("?")[1];
uid = C1.split("=")[1];
let vue = new Vue({
el: "#updateContains",
data() {
return {
user: {
tbid:"",
tbUsername: "",
tbZhanghao: "",
tbPassword: "",
tbGender: "",
tbAddress: "",
tbAge: "",
tbBirthday: "",
},
code: {
checkCode: ""
}
};
},
methods: {
findById() {
var _this = this
axios({
method: "get",
url: "/users/" + uid
}).then(function (resp) {
_this.user.id = resp.data.data.id
_this.user.tbUsername = resp.data.data.tbUsername
_this.user.tbZhanghao = resp.data.data.tbZhanghao
_this.user.tbPassword = resp.data.data.tbPassword
_this.user.tbGender = resp.data.data.tbGender
_this.user.tbAddress = resp.data.data.tbAddress
_this.user.tbAge = resp.data.data.tbAge
_this.user.tbBirthday = resp.data.data.tbBirthday
})
},
updateuser() {
axios({
method: "put",
url: "/users",
data: vue.user
}).then(function (resp) {
if (resp.data.msg == "success") {
location.href = "/pages/user.html"
} else {
alert("这测失败");
}
})
}
},
mounted() {
this.findById();
}
});
</script>
</body>
</html>
addUser.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加操作</title>
</head>
<body>
<div id="addContains">
<form id="form" action="" method="post">
用户名:<input type="text" id="username" v-model="user.tbUsername"><br>
账号:<input type="text" id="zhanghao" v-model="user.tbZhanghao"><br>
密码:<input type="password" id="password" v-model="user.tbPassword"><br>
性别:<input type="radio" value="0" v-model="user.tbGender">男
<input type="radio" value="1" v-model="user.tbGender">女
<br>
地址:<input type="text" id="address" v-model="user.tbAddress"><br>
年龄:<input type="text" id="age" v-model="user.tbAge"><br>
生日:<input type="date" id="birthday" v-model="user.tbBirthday"><br>
<button type="button" id="bt" value="bt" @click="adduser()">添加</button>
</form>
</div>
<script src="../js/vue.js"></script>
<script src="../js/axios-0.18.0.js"></script>
<script>
let vue = new Vue({
el: "#addContains",
data() {
return {
user: {
tbUsername: "",
tbZhanghao: "",
tbPassword: "",
tbGender: "",
tbAddress: "",
tbAge: "",
tbBirthday: "",
},
code: {
checkCode: ""
}
};
},
methods: {
adduser() {
axios({
method:"post",
url:"/users",
data:vue.user
}).then(function (resp){
if(resp.data.msg == "success"){
location.href="/pages/user.html"
}else{
alert("这测失败");
}
})
}
}
});
</script>
</body>
</html>
直接在代码注释中有描述:
test:
“Users::getTbAge”,这种格式可以理解为,表示数据库中的tb_age这个字段
@SpringBootTest
class Day08MybatisPlusApplicationTests {
@Autowired
UserDao userDao;
@Autowired
Users users;
@Test
void findAll() {
List<Users> usersList = userDao.selectList(null);
System.out.println(usersList);
}
@Test
void testFindByPage(){
IPage<Users> page = new Page<>(1,2);
IPage<Users> iPage = userDao.selectPage(page,null);
System.out.println("一共多少页"+iPage.getPages());
System.out.println("当前页:"+iPage.getCurrent());
System.out.println("每页显示个数:"+iPage.getSize());
System.out.println("数据总数:"+iPage.getTotal());
System.out.println("数据:"+iPage.getRecords());
}
@Test
// 测试调剂查询,lt是小于号,gt是大于号
public void testselectByCondition(){
// 准备数据,模拟前端页面传过来的数据
users.setTbAge(10);
LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
// 进行空判断以及大小判断
// lqw.gt(null != users.getTbAge(),Users::getTbAge,users.getTbAge());
// 表示and的条件查询,大于10岁并且小于30岁
// users.getTbAge()表示前端页面的值
/* lqw.gt(null != users.getTbAge(),Users::getTbAge,users.getTbAge())
.lt(Users::getTbAge,30);
相当于sql语句 select * from users
tb_age ">"(大于号当然不是这样写的^_^) users.getTbAge()
*/
// 表示or 的条件查询,小于10岁或者大于15
lqw.lt(null != users.getTbAge(),Users::getTbAge,users.getTbAge())
.or().gt(Users::getTbAge,30);
List<Users> usersList = userDao.selectList(lqw);
System.out.println(usersList);
}
@Test
public void testSelectById(){
// LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
// queryWrapper.eq(Users::getTbUid,2);
// Users users = userDao.selectOne(queryWrapper);
// System.out.println(users);
Users users = userDao.selectById(2);
System.out.println(users);
}
}