使用 Swagger2 进行接口测试
启动项目访问 http://127.0.0.1:8080/swagger-ui.html ,即可打开自动生成的可视化测试页面
Swagger常用注解
Swagger提供了一系列注解来描述接口信息,包括接口说明、请求方法、请求参数、返回信息等
MybatisPlus快速上手
ORM介绍
- ORM(Object Relational Mapping,对象关系映射)是为了解决面向对象与关系数据库存在的互不匹配现象的一种技术。
- ORM通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系数据库中。
- ORM框架的本质是简化编程中操作数据库的编码。
MyBatis-Plus介绍
- MyBatis是一款优秀的数据持久层ORM框架,被广泛地应用于应用系统。
- MyBatis能够非常灵活地实现动态SQL,可以使用XML或注解来配置和映射原生信息,能够轻松地将Java的POJO(Plain Ordinary Java Object,普通的Java对象)与数据库中的表和字段进行映射关联。
- MyBatis-Plus是一个 MyBatis 的增强工具,在 MyBatis 的基础上做了增强,简化了开发。
<!--Mybatis Plus 依赖--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <!--MySQL 驱动依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--数据连接池druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.20</version> </dependency>
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false spring.datasource.druid.username=root spring.datasource.druid.password=root mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
@SpringBootApplication @MapperScan("com.demo.mapper") public class MybatisPlusDemo Application{ public static void main(String [] args){ SpringApplication.run(MybatisPlusApplication.class, args); } }
MyBatis-Plus CRUD操作
//package com.example.demo.mapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserMapper { @Select("select * from user") public List<User> findAll(); @Insert("insert into user values(#{id}, #{name}, #{age})") public int add(User user); @Update("update user set id=#{id}, name=#{name}, age=#{age}") public int update(User user); @Delete("delete from user where id=#{id}") public int delete(int id); @Select("select * from user where id=#{id}") public User findById(int id); }
package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class UserController { @Autowired private UserMapper userMapper; @GetMapping("/user") public List<User> findAll() { return userMapper.findAll(); } @PostMapping("/saveUser") public String save(User user){ int flag = userMapper.add(user); if (flag > 0) return "插入成功"; else return "插入失败"; } }
Spring的三种注入方式:
构造注入,getter和setter注入,自动注入
package com.example.demo.entity; public class User { private int id; private String name; private int age; public User(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
数据库字段和实体类字段映射规则
MybatisPlus注解
- @TableName,当表名与实体类名称不一致时,可以使用@TableName注解进行关联。
- @TableField,当表中字段名称与实体类属性不一致时,使用@TableField进行关联
- @TableId,用于标记表中的主键字段,MybatisPlus也提供了主键生成策略。
package com.example.demo.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @TableName("user") public class User { @TableId(type = IdType.AUTO) private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
多表查询及分页查询
多表查询
实现复杂关系映射,可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置。
分页查询
编写配置文件
package com.example.demo.config; import com.baomidou.mybatisplus.annotation.DbType; 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 paginationInterceptor(){ MybatisPlusInterceptor intercepter = new MybatisPlusInterceptor(); PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); intercepter.addInnerInterceptor(paginationInnerInterceptor); return intercepter; } }
测试
package com.example.demo.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; @RestController public class UserController { @Resource private UserMapper userMapper; @GetMapping("/user") public List<User> findAll() { return userMapper.findAll(); } @PostMapping("/saveUser") public String save(User user) { int flag = userMapper.add(user); if (flag > 0) return "插入成功"; else return "插入失败"; } @GetMapping("/user-orders") public List<User> getUserAllOrders() { return userMapper.selectAllUserAndOrders(); } // 条件查询 @GetMapping("/user/find") public List<User> findByCond() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name", "zhangsan"); return userMapper.selectList(queryWrapper); } // 分页查询 @GetMapping("/user/findByPage") public IPage findByPage() { // 设置起始值及每页条数 Page<User> page = new Page<>(0, 2); IPage ipage = userMapper.selectPage(page, null); return ipage; } }
package com.example.demo.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import java.util.Date; @TableName("orders") public class Order { private int oid; private Date date; private int cid; @TableField(exist = false) private User user; public int getOid() { return oid; } public void setOid(int oid) { this.oid = oid; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public int getCid() { return cid; } public void setCid(int cid) { this.cid = cid; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Order{" + "oid=" + oid + ", date=" + date + ", cid=" + cid + '}'; } }
package com.example.demo.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.util.List; @TableName("user") public class User { @TableId(type = IdType.AUTO) private int id; private String name; private int age; //告诉Mybatis不做映射 @TableField(exist = false) private List<Order> orders; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
package com.example.demo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.demo.entity.Order; import com.example.demo.entity.User; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface OrderMapper extends BaseMapper<Order> { @Select("select * from orders where cid = #{cid}") public List<Order> selectByUid(int id); // 查询所有的订单,同时查询订单的用户 @Select("select * from order") @Results({ @Result(column = "oid", property = "oid"), @Result(column = "date", property = "date"), @Result(column = "uid", property = "user", javaType = User.class, one = @One(select = "com.example.demo.mapper.UserMapper.selectById")) }) public List<Order> selectAllOrdersAndUser(); }
package com.example.demo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserMapper extends BaseMapper<User> { @Select("select * from user") public List<User> findAll(); @Insert("insert into user values(#{id}, #{name}, #{age})") public int add(User user); @Update("update user set id=#{id}, name=#{name}, age=#{age}") public int update(User user); @Delete("delete from user where id=#{id}") public int delete(int id); @Select("select * from user where id=#{id}") public User findById(int id); // 查询用户所有订单 @Select("select * from user") @Results( { @Result(column = "id", property = "id"), @Result(column = "name", property = "name"), @Result(column = "age", property = "age"), @Result(column = "id", property = "orders", javaType = List.class, many = @Many(select = "com.example.demo.mapper.OrderMapper.selectByUid")) } ) public List<User> selectAllUserAndOrders(); }
Vue快速上手
前端环境准备
- 编码工具:VSCode
- 依赖管理:NPM
- 项目构建:VueCli
Vue框架介绍
- Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。
- Vue.js提供了MVVM数据绑定和一个可组合的组件系统,具有简单、灵活的API。
- 其目标是通过尽可能简单的API实现响应式的数据绑定和可组合的视图组件。
MVVM模式
- MVVM是Model-View-ViewModel的缩写,它是一种基于前端开发的架构模式,其核心是提供对View和ViewModel的双向数据绑定。
- Vue提供了MVVM风格的双向数据绑定,核心是MVVM中的VM,也就是ViewModel,ViewModel负责连接View和Model,保证视图和数据的一致性。
Vue快速入门
导入 vue.js 的 script 脚本文件
<script src="https://unpkg.com/vue@next"></script>
在页面中声明一个将要被 vue 所控制的 DOM 区域,既MVVM中的View
<div id="app"> {{message}} </div>
创建 vm 实例对象(vue 实例对象)
const Hello = { //指定数据源,即MVVM中的Model data: function(){ return { "message": "Hello Vue!" } } } const app = Vue.createApp(Hello) app.mount('#app') //指定当前Vue实例要控制页面的哪个区域
基本用法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <!-- 1. 导入 vue 的脚本文件 --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <!-- 2. 声明要被 vue 所控制的 DOM 区域 --> <div id="app"> {{message}} </div> <!-- 3. 创建 vue 的实例对象 --> <script> const hello = { // 指定数据源,既MVVM中的Model data: function() { return { message: 'Hello Vue!' } } } const app = Vue.createApp(hello) app.mount('#app') </script> </body> </html>
内容渲染命令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <p>姓名:{{username}}</p> <p>性别:{{gender}}</p> <p>{{desc}}</p> <!--将html元素字符串转换成标签--> <p v-html="desc"></p> </div> <script> const vm = { data: function(){ return { username: 'zhangsan', gender: '男', desc: '<a href="http://www.baidu.com">百度</a>' } } } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>
属性绑定指令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <a :href="link">百度</a> <input type="text" :placeholder="inputValue"> <img :src="imgSrc" :style="{width:w}" alt=""> </div> <script> const vm = { data: function(){ return { link:"http://www.baidu.com", // 文本框的占位符内容 inputValue: '请输入内容', // 图片的 src 地址 imgSrc: './images/demo.png', w:'500px' } } } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>
使用JavaScript表达式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <!-- vue 实例要控制的 DOM 区域 --> <div id="app"> <p>{{number + 1}}</p> <p>{{ok ? 'True' : 'False'}}</p> <p>{{message.split('').reverse().join('')}}</p> <p :id="'list-' + id">xxx</p> <p>{{user.name}}</p> </div> <script> const vm = { data: function(){ return { number: 9, ok: false, message: 'ABC', id: 3, user: { name: 'zs', } } } } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>
事件绑定指令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <h3>count 的值为:{{count}}</h3> <button v-on:click="addCount">+1</button> <button @click="count+=1">+1</button> <!-- <button @click="addCount">+1</button> --> </div> <script> const vm = { data: function(){ return { count: 0, } }, methods: { // 点击按钮,让 count 自增 +1 addCount() { this.count += 1 }, }, } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>
条件渲染指令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <button @click="flag = !flag">Toggle Flag</button> <!--当状态只更改一次时,建议用v-if,当状态频繁更改时,建议用v-show--> <p v-if="flag">请求成功 --- 被 v-if 控制</p> <p v-show="flag">请求成功 --- 被 v-show 控制</p> </div> <script> const vm = { data: function(){ return { flag: false, } } } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>
v-else和v-else-if指令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <p v-if="num > 0.5">随机数 > 0.5</p> <p v-else>随机数 ≤ 0.5</p> <hr /> <p v-if="type === 'A'">优秀</p> <p v-else-if="type === 'B'">良好</p> <p v-else-if="type === 'C'">一般</p> <p v-else>差</p> <div v-show="a"> 测试 </div> <button @click="!a">点击</button> </div> <script> const vm = { data: function(){ return { // 生成 1 以内的随机数 num: Math.random(), // 类型 type: 'A', a : false } }, methods:{ f:function(){ this.a = !this.a } } } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>
列表渲染指令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <ul> <li v-for="(user, i) in userList">索引是:{{i}},姓名是:{{user.name}}</li> </ul> </div> <script> const vm = { data: function(){ return { userList: [ { id: 1, name: 'zhangsan' }, { id: 2, name: 'lisi' }, { id: 3, name: 'wangwu' }, ], } }, } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>
v-for中的key
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <!-- 添加用户的区域 --> <div> <input type="text" v-model="name"> <button @click="addNewUser">添加</button> </div> <!-- 用户列表区域 --> <ul> <li v-for="(user, index) in userlist" :key="user.id"> <input type="checkbox" /> 姓名:{{user.name}} </li> </ul> </div> <script> const vm = { data: function(){ return { // 用户列表 userlist: [ { id: 1, name: 'zhangsan' }, { id: 2, name: 'lisi' } ], // 输入的用户名 name: '', // 下一个可用的 id 值 nextId: 3 } }, methods: { // 点击了添加按钮 addNewUser() { this.userlist.unshift({ id: this.nextId, name: this.name }) this.name = '' this.nextId++ } } } const app = Vue.createApp(vm) app.mount('#app') </script> </body> </html>