目录
一.Vue工程
安装NodeJS与Vue-cli
Vue项目创建
启动Vue项目:点击npm脚本serve
改端口:在vue.config.js下
Vue文件组成:template+script+style
使用element
前端服务器当前使用Ngix
主要编写的文件
二.SpringBoot的Web工程
启动带有@SpringBootApplication注解的类来启动服务,这个启动类包含了包扫描,会扫描该类所在包与其子包的所有类
各类请求的接收与各类响应的发送
入门请求
简单参数
实体参数
复杂实体类参数
数组参数:数组接收与集合接收
时间参数
json参数
动态参数
响应数据转变成json
使用Result统一管理响应数据
案例:请求员工数据
直接访问
分层访问
在SpringBoot当中解耦
使用IOC第一步:给需要的方案加上@Component或者其衍生注解
步骤二:在需要创建的变量上加上@autowired注解自动装配
问题:如果有多个该类型的Bean对象,会报错(多个EmpDao)
最后的控制层:
下方自带可以查看所有Spring中的Bean的工具
三. 数据库查漏补缺
1.使用函数可以记录现在的时间
2.查询空where *** is null ,不能用等于
3.根据条件给行中的数据起别名
5.子条件为一行
6.在多表查询时可以使用表名.*代替某张表中所有的列
创建查询删除索引
四.在SpringBoot项目中使用MyBatis
配置信息:
案例一:查询所有用户
案例二:员工增删改查
一.根据id删除,#{}是预编译sql,使用$则是应对动态修改表名或列
二.拿到生成的主键值,并且将生成的主键值复制到Emp对象的id属性中
三.更新数据,在java代码中存储当前时间
四.查询数据无需使用Results配置数据库表与实体类属性的映射关系,在配置文件中配置即可,在xml文件中的foreach里面也能直接使用变量名表示传进来的变量
五.多个参数不需要注解(使用2.x的springboot且继承mybatis),不能把#{}放在引号,故此处使用concat函数
六.在xml文件中需要了解sql标签和include标签:可用与长sql的复用
一.Vue工程(VSCode)
安装NodeJS与Vue-cli
Vue-cli是Vue官方提供的一个脚手架,用于快速生成Vue的项目模板,依赖于NodeJS
1.安装Node.js,检查:node -v
2.npm set prefix "D:\NodeJS",检查:npm get prefix
3.npm config set registry https://registry.npmmirror.com
4.npm install -g @vue/cli,检查:vue --version
Vue项目创建
1.新建目录cmd:vue ui
2.详情界面选择npm
3.预设界面选择手动
4.功能界面添加router
5.配置选择2版本,liner选择第一个
启动Vue项目:点击npm脚本serve
改端口:在vue.config.js下
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
//修改端口
devServer:{
port: 7000,
}
})
Vue文件组成:template+script+style
Home.Vue:
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
components: {
HelloWorld
}
}
</script>
使用element
1.安装element组件库与axios
PS D:\VS Codes\JavaWeb\VueDemo\demo1> npm install element-ui@2.15.3
PS D:\VS Codes\JavaWeb\VueDemo\demo1> npm install axios
2.修改main.js
import Vue from 'vue'
import App from './App.vue'
//导入路由信息
import router from './router'
//导入element
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false
Vue.use(ElementUI)
//在创建Vue时制定了路由
new Vue({
router,
render: h => h(App)
}).$mount('#app')
前端服务器当前使用Ngix
项目打包:点击build脚本,打包之后的项目放在dist文件下,把dist目录下的资源部署在服务器(html目录)下
启动Ngix之后服务器默认占用80端口号,被系统占用,改配置文件中http-server-listen的80->10000
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 10000;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
主要编写的文件
使用router实现资源的切换
router下的index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
/*
实现页面切换功能
前端路由:URL中的hash与组件之间的对应关系
VueRouter:Vue的官方路由,路由器类,包含了路由表,根据路由请求(URL)在路由视图中动态渲染的组件(显示)
router-link:请求链接组件,浏览器会请求为<a>
router-view:动态视图组件,可以在任何区域展示与这个url对应的组件
*/
Vue.use(VueRouter)
const routes = [
//在这里配置路由信息
{
path: '/emp',
name: 'emp',
component: () => import('../views/element/empView.vue')
},
{
path: '/dept',
name: 'dept',
component: () => import('../views/element/deptView.vue')
},
{
path: '/element',
name: 'element',
component: () => import('../views/element/elementView.vue')
},
//配置根路径:防止找不到首页
{
path: '/',
redirect: '/dept'
}
]
const router = new VueRouter({
routes
})
export default router
deptView:
<template>
<div>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size:40px; background-color: rgb(238, 241, 246)">智能学习辅助系统</el-header>
<el-container>
<el-aside width="200px" style="border: 1px solid #eee">
<el-menu :default-openeds="['1']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>系统信息管理</template>
<el-menu-item index="1-1">
<!-- 访问不同路由 -->
<router-link to="/dept">部门管理</router-link>
</el-menu-item>
<el-menu-item index="1-2">
<router-link to="/emp">员工管理</router-link>
</el-menu-item>
<el-menu-item index="1-3">
<router-link to="/element">element元素</router-link>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<!-- 表格 -->
<el-table :data="tableData" border>
<el-table-column prop="name" label="名称" width="250"></el-table-column>
<el-table-column prop="updatetime" label="最后操作时间" width="250"></el-table-column>
<el-table-column label="操作">
<el-button type="primary" size="mini">编辑</el-button>
<el-button type="danger" size="mini">删除</el-button>
</el-table-column>
</el-table>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [{
id: 1,
name: "学工部",
updatetime: "2010-01-01 12:00:00"
}, {
id: 2,
name: "教研部",
updatetime: "2010-01-01 12:00:00"
}, {
id: 3,
name: "就业部",
updatetime: "2010-01-01 12:00:00"
}, {
id: 4,
name: "人事部",
updatetime: "2010-01-01 12:00:00"
}, {
id: 5,
name: "行政部",
updatetime: "2010-01-01 12:00:00"
}]
}
},
methods: {
}
}
</script>
<style></style>
template>
<div>
<!-- 按钮组件 -->
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
<br />
<!-- 表格组件 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
<br />
<!-- 分页组件 -->
<!-- 统计,每页规模,前一页,页面,后一页,跳转页 -->
<!-- 添加事件 -->
<el-pagination
background
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="1000"
>
</el-pagination>
<br />
<!-- Dialog对话框+表单-->
<el-button type="text" @click="dialogFormVisible = true"
>打开嵌套表单的 Dialog</el-button
>
<el-dialog title="收货地址" :visible.sync="dialogFormVisible">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker
type="date"
placeholder="选择日期"
v-model="form.date1"
style="width: 100%"
></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker
placeholder="选择时间"
v-model="form.date2"
style="width: 100%"
></el-time-picker>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!-- 表单 -->
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
},
{
date: "2016-05-04",
name: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
},
],
form: {
name: "",
region: "",
date1: "",
date2: "",
},
dialogFormVisible: false,
};
},
methods: {
handleSizeChange: function (val) {
alert("每页记录数变化" + val);
},
handleCurrentChange: function (val) {
alert("页码发生变化" + val);
},
onSubmit() {
alert(JSON.stringify(this.form));
},
},
};
</script>
<style>
</style>
<template>
<div>
<el-container style="height: 500px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)">
智能学习辅助系统
</el-header>
<el-container>
<el-aside width="200px" style="border: 1px solid #eee">
<el-menu :default-openeds="['1']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>系统信息管理</template>
<el-menu-item index="1-1">
<!-- 访问不同路由 -->
<router-link to="/dept">部门管理</router-link>
</el-menu-item>
<el-menu-item index="1-2">
<router-link to="/emp">员工管理</router-link>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<el-form :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="姓名">
<el-input v-model="searchForm.user" placeholder="姓名"></el-input>
</el-form-item>
<el-form-item label="性别">
<el-select v-model="searchForm.gender" placeholder="性别">
<el-option label="男" value="1"></el-option>
<el-option label="女" value="2 "></el-option>
</el-select>
</el-form-item>
<el-form-item label="入职日期">
<el-date-picker v-model="searchForm.entrydate" type="daterange" range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
<el-table :data="tableData" border="">
<el-table-column prop="name" label="姓名" width="180"></el-table-column>
<el-table-column prop="image" label="图像" width="180">
<template slot-scope="scope">
<img :src="scope.row.image" width="100px" height="70px">
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" width="140">
<!-- 插槽 -->
<template slot-scope="scope">{{ scope.row.gender == 1 ? "男" : "女" }}</template>
</el-table-column>
<el-table-column prop="job" label="职位" width="140"></el-table-column>
<el-table-column prop="entrydate" label="入职日期" width="180"></el-table-column>
<el-table-column prop="updatetime" label="最后操作时间" width="230"></el-table-column>
<el-table-column label="操作">
<el-button type="primary" size="mini">编辑</el-button>
<el-button type="danger" size="mini">删除</el-button>
</el-table-column> </el-table><br />
<el-pagination background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
@current-change="handleCurrentChange" :total="1000">
</el-pagination>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
tableData: [],
searchForm: {
name: "",
gender: "",
entrydate: [],
},
};
},
methods: {
onSubmit: function () {
alert("查询数据");
},
handleSizeChange: function (val) {
alert("每页记录数变化" + val);
},
handleCurrentChange: function (val) {
alert("页码发生变化" + val);
},
},
mounted() {
//发送异步请求获取数据
axios
.get("https://mock.apifox.cn/m1/3128855-0-default/emp/list")
.then((result) => {
this.tableData = result.data.data;
});
},
};
</script>
<style></style>
二.SpringBoot的Web工程
Spring提供了若干个子项目,每个项目用于完成特定功能
基础底层框架就是Spring Framework(Spring核心)
SpringBoot免去了Framework配置繁琐、学习难度大的问题,简化配置,快速开发
创建springboot项目的时候使用SpringWeb,在sb里面已经集成了汤猫自动打开服务器
postman:发送网页http请求的插件,用于接口测试
启动带有@SpringBootApplication注解的类来启动服务,这个启动类包含了包扫描,会扫描该类所在包与其子包的所有类
@SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
}
各类请求的接收与各类响应的发送
接下来的代码写在RequestController里面
@RestController
public class RequestController {
}
入门请求
1.浏览器访问@RequestMapping注解里的地址调用此方法 2.返回代表响应数据
@RequestMapping("/hello")
public String hello(){
System.out.println("Hello world");
return "Hello world";
}
简单参数
1.在访问路径中也能传递请求参数 2.通过注解可以指定请求参数的名字,也可动态设置请求参数 3.注解@RequestParam中的的参数表示是否一定需要,默认为true,可设置为false 4.无论是get请求还是post请求都可以对请求参数进行处理
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name="name",required = false) String username, int age){
return username+":"+age;
}
实体参数
可以把形参写成实体类对象,不需要类的全部参数,请求不变。
public class Address {
private String province;
private String city;
public Address() {
}
public Address(String province, String city) {
this.province = province;
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String toString() {
return "Address{province = " + province + ", city = " + city + "}";
}
}
public class User {
private String name;
private Integer age;
private Address address;
public User() {
}
public User(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
@RequestMapping("/pojoParam")
public String pojoParam(User user){
return user.toString();
}
复杂实体类参数
复杂实体参数,类中内部类,请求使用【实体类属性.内部类】属性发送
@RequestMapping("/complexPojo")
public String complexPojo(User user){
return user.toString();
}
数组参数:数组接收与集合接收
请求参数中,同key不同value参数的接收
也能用集合接收,需要加注解(因为默认封装到数组当中)
时间参数
时间需要注解格式
@RequestMapping("/timeParam")
public String timeParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")LocalDateTime updateTime){
return updateTime.toString();
}
json参数
传递json参数需要使用RequestBody注解使用实体类接收,请求需要使用post
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
return user.toString();
}
动态参数
1.动态获取参数路径参数需要在请求mapping注解的路径中给变化的参数加上{} 2.在方法中需要给参数加上@PathVariable注解 3.请求路径中的参数有变化,如path/1...10
@RequestMapping("/pathParam/{id}")
public String pathParam(@PathVariable Integer id){
return id.toString();
}
//多个路径参数
@RequestMapping("/pathParam/{id}/{name}")
public String pathParam2(@PathVariable Integer id,@PathVariable String name){
return id+":"+name;
}
接下来的代码在ResponseController里面
@RestController
public class ResponseController {
}
响应数据转变成json
响应方法返回的数据,对象自动转json,需要在方法上写上对应的返回类型,前面的案例全是字符串
@RequestMapping("/getAddrList")
public List<Address> getArrList(){
List<Address> list= new ArrayList<>();
Collections.addAll(list,new Address("广东","深圳"),new Address("湖南","长沙"));
return list;
}
使用Result统一管理响应数据
public class Result {
//多了几个静态方法用来快速构造对象
private Integer code ;//1 成功 , 0 失败
private String msg;
private Object data;
public static Result success(Object data){
return new Result(1, "success", data);
}
public static Result success(){
return new Result(1, "success", null);
}
public static Result error(String msg){
return new Result(0, msg, null);
}
public Result() {
}
public Result(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
@RequestMapping("/getResult")
public Result getResult(){
return Result.error("哎哟你干嘛");
}
案例:请求员工数据
1.引入dom4j依赖<dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.4</version> </dependency>
2.创建Emp实体类public class Emp { private String name; private Integer age; private String image; private String gender; private String job; public Emp() { } public Emp(String name, Integer age, String image, String gender, String job) { this.name = name; this.age = age; this.image = image; this.gender = gender; this.job = job; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } @Override public String toString() { return "Emp{" + "name='" + name + '\'' + ", age=" + age + ", image='" + image + '\'' + ", gender='" + gender + '\'' + ", job='" + job + '\'' + '}'; } }
3.引入xml文件<?xml version="1.0" encoding="UTF-8" ?> <emps> <emp> <name>金毛狮王</name> <age>55</age> <image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/1.jpg</image> <gender>1</gender> <job>1</job> </emp> <emp> <name>白眉鹰王</name> <age>65</age> <image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/2.jpg</image> <gender>1</gender> <job>1</job> </emp> <emp> <name>青翼蝠王</name> <age>45</age> <image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/3.jpg</image> <gender>1</gender> <job>2</job> </emp> <emp> <name>紫衫龙王</name> <age>38</age> <image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/4.jpg</image> <gender>2</gender> <job>3</job> </emp> </emps>
4.引入工具类(这个使用到了反射)public class XmlParserUtils { public static <T> List<T> parse(String file , Class<T> targetClass) { ArrayList<T> list = new ArrayList<T>(); try { for (Element element : new SAXReader().read(new File(file)).getRootElement().elements("emp")) { Constructor<T> constructor = targetClass.getDeclaredConstructor(String.class, Integer.class, String.class, String.class, String.class); constructor.setAccessible(true); T object = constructor.newInstance(element.element("name").getText(), Integer.parseInt(element.element("age").getText()), element.element("image").getText(), element.element("gender").getText(), element.element("job").getText()); list.add(object); } } catch (Exception e) { e.printStackTrace(); } return list; } }
直接访问
//请求路径和html页面中的路径一样,写好访问路径
@RequestMapping("/listEmp")
public Result getEmp(){
//获取的打包后的classes目录下的文件
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
empList.forEach(emp -> {
if ("1".equals(emp.getGender()))emp.setGender("男");
else emp.setGender("女");}
);
return Result.success(empList);
}
分层访问
web当中的三层架构
controller控制层:接受请求,数据处理,响应数据
service:业务逻辑处理
dao数据访问层(data Access Object):数据库增删改查
对于DAO与Service需要编写接口(方便修改 )
DAO层:
public interface EmpDao {
List<Emp> listEmp();
}
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
return XmlParserUtils.parse(file, Emp.class);
}
}
Service 层:
public interface EmpService {
List<Emp> listEmp();
}
public class EmpServiceA implements EmpService {
//面向接口编程,写在类最前方便多次调用
private EmpDao empDao = new EmpDaoA();
@Override
public List<Emp> listEmp() {
List<Emp> empList = empDao.listEmp();
empList.forEach(emp -> {
if ("1".equals(emp.getGender()))emp.setGender("男");
else emp.setGender("女");
}
);
return empList;
}
}
@RequestMapping("/listEmp1")
public Result getEmp1(){
return Result.success(empService.listEmp());
}
在SpringBoot当中解耦
高内聚:如在员工服务层里只处理员工这个类的信息,不会处理其他类
低耦合:在服务层中只用到了dao层的对象,尽量少调用别的对象,最佳的方案是解除耦合
在之前的方案中,服务层在调用dao层时使用到了dao层的实现类
使用不同的调用数据方法要改变服务层中的代码,解耦方案如下:
创建一个容器,把需要用到的实现类放进去,无需使用的搁置即可,这就需要spring中几个重要的概念
控制反转:Inversion of Control IOC:对象创建的控制权由程序转移到程序外部的容器,也就是说不需要您去亲自创建类的对象了
依赖注入:Dependency Injection DI:容器提供对象给某个变量 ,SpringBoot帮您做好,想要用就帮您送过来
Bean对象:IOC容器中管理的对象:也就是SpringBoot帮您管理的类
声明Bean的基础注解:@Component
由Component衍生出的三个注解(推荐使用)
Dao层:@Repository
Service层:@Service
Controller层:@Controller
@RestController:@Controller+@ResponseBody(方法返回值转变JSON返回)
使用IOC第一步:给需要的方案加上@Component或者其衍生注解
@Repository
public class EmpDaoB implements EmpDao {
@Override
public List<Emp> listEmp() {
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
return XmlParserUtils.parse(file, Emp.class);
}
}
步骤二:在需要创建的变量上加上@autowired注解自动装配
@Service
public class EmpServiceB implements EmpService {
@Autowired
private EmpDao empDao;
@Override
public List<Emp> listEmp() {
List<Emp> empList = empDao.listEmp();
empList.forEach(emp -> {
if ("1".equals(emp.getGender()))emp.setGender("男");
else emp.setGender("女");
}
);
return empList;
}
}
问题:如果有多个该类型的Bean对象,会报错(多个EmpDao)
解决方法一:在EmpDao的实现类加Primary注解来声明需要优先使用哪一个实现类//指定老大实现类 @Primary @Repository public class EmpDaoC implements EmpDao { @Override public List<Emp> listEmp() { System.out.println("EmpDaoC"); String file = this.getClass().getClassLoader().getResource("emp.xml").getFile(); return XmlParserUtils.parse(file, Emp.class); } }
解决方法二:在自动装配注解前加Qualifier注解指定需要使用的实现类,注意类名要小写(没有指定Bean的名字的话)@Qualifier("empDaoC")
解决方法三:使用Resource注解:相当于qualifier+autowired,需要直接指定名称@Resource(name = "empDaoC")
最后的控制层:
@RestController
public class IOCController {
@Autowired
EmpService empService;
@RequestMapping("/listEmp2")
public Result getEmp2(){
return Result.success(empService.listEmp());
}
}
下方自带可以查看所有Spring中的Bean的工具
三. 数据库查漏补缺
1.使用函数可以记录现在的时间
insert into tb_user (username,name,gender,create_time,update_time)values('zhangsan','张三',23,now(),now());
2.查询空where *** is null ,不能用等于
3.根据条件给行中的数据起别名
select if(gender=1,'男性员工','女性员工') 性别,count(*) from tb_emp group by gender;
4.select case job
when 1 then '班主任'
when 2 then '讲师'
when 3 then '学工主管'
when 4 then '教研主管'
else '未分配职位'
end '职位' ,count(*)
from tb_emp group by job;
5.子条件为一行
select * from tb_emp where(entrydate,job)=('2007-01-01',2)
select * from tb_emp where(entrydate,job)
=(select entrydate,job from tb_emp wherename='韦一笑')
6.在多表查询时可以使用表名.*代替某张表中所有的列
创建查询删除索引
索引用来提高查询效率,在底层给列创建新的数据结构
主键,唯一约束会默认创建索引
create index idx_name on tb_dept(name)
show index from tb_dept
drop index idx_name on tb_dept
B+树:多路平衡搜索树,子树可以有多个
所有的数据都在叶子节点(方便查询稳定)
叶子节点之间形成双向链表方便排序
四.在SpringBoot项目中使用MyBatis
在创建项目的时候也能集成mybatis,mysqlDriver,lombok
配置信息:
主要内容为配置数据库数据,mybatis输出日志,给表名与类属性做映射
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/db1
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456
#配置mybatis的日志信息,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#开启myBatis驼峰命名自动映射开关,不需要映射注解,也不需要写xml配置文件
mybatis.configuration.map-underscore-to-camel-case=true
案例一:查询所有用户
在mapper接口上注解
@Mapper//在运行时自动生成实现类对象(动态代理对象),并且将该对象文件交给IOC容器处理
public interface UserMapper {
@Select("select * from user")
List<User> selectAll();
}
使用lombok快速构造实体类
@Data//生成getter/setter+toString+EqualsAndHashCode方法
@NoArgsConstructor//生成无参构造方法
@AllArgsConstructor//生成全参构造
public class User {
private Integer id;
private String name;
private Integer age;
private Integer gender;
private String phone;
}
在测试类中:
@Autowired
private UserMapper userMapper;
@Test
void test() {
System.out.println(userMapper.selectAll());
}
案例二:员工增删改查
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id;
private String username;
private String password;
private String name;
private Short gender;
private String image;
private Short job;
private LocalDate entrydate;
private Integer deptId;
private LocalDateTime createTime;
private LocalDateTime updateTime;
public Emp(String username, String name, Short gender, String image, Short job, LocalDate entrydate, Integer deptId, LocalDateTime createTime, LocalDateTime updateTime) {
this.username = username;
this.name = name;
this.gender = gender;
this.image = image;
this.job = job;
this.entrydate = entrydate;
this.deptId = deptId;
this.createTime = createTime;
this.updateTime = updateTime;
}
}
在下列的mapper中:
@Mapper
public interface EmpMapper {
}
一.根据id删除,#{}是预编译sql,使用$则是应对动态修改表名或列名
@Delete("delete from emp where id = #{id} ")
public int deleteById(Integer id);
@Test
void delete(){
System.out.println(empMapper.deleteById(19));
}
二.拿到生成的主键值,并且将生成的主键值复制到Emp对象的id属性中
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("INSERT into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) VALUES " +
"(#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
public void insert(Emp emp);
@Test
void insert(){
Emp emp = new Emp("zhangsan1","张三1", (short) 1,"1.jpg", (short) 1,
LocalDate.of(2024,3,10),1,
LocalDateTime.now(), LocalDateTime.now());
empMapper.insert(emp);
System.out.println(emp.getId());
}
三.更新数据,在java代码中存储当前时间
@Update("Update emp set username=#{username},name=#{name},gender=#{gender},image=#{image},job=#{job},entrydate=#{entrydate},dept_id=#{deptId},update_time=#{updateTime} where id =#{id};")
public void update(Emp emp);
@Test
void update(){
Emp emp = new Emp(21,"zhangsan2","123456","张三2", (short) 1,"1.jpg", (short) 1,
LocalDate.of(2024,3,10),1,
LocalDateTime.now(), LocalDateTime.now());
empMapper.update(emp);
}
四.查询数据无需使用Results配置数据库表与实体类属性的映射关系,在配置文件中配置即可,在xml文件中的foreach里面也能直接使用变量名表示传进来的变量
@Select("Select * from emp where id = #{id}")
public Emp selectById(Integer id);
@Test
void selectById(){
Emp emp = empMapper.selectById(1);
System.out.println(emp);
}
五.多个参数不需要注解(使用2.x的springboot且继承mybatis),不能把#{}放在引号,故此处使用concat函数
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> selectByMany(String name, Short gender, LocalDate begin, LocalDate end);
@Test
void selectByMany(){
List<Emp> emps = empMapper.selectByMany
("张", (short) 1,
LocalDate.of(2010, 1, 1),
LocalDate.of(2030, 1, 1));
System.out.println(emps);
}
六.在xml文件中需要了解sql标签和include标签:可用与长sql的复用
public List<Emp> selectByCondition(String name, Short gender, LocalDate begin, LocalDate end);
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.springbootdemo2.mapper.EmpMapper">
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
</sql>
<select id="selectByCondition" resultType="org.example.springbootdemo2.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name!=null and name!=''">
name like concat ('%',#{name},'%')
</if>
<if test="gender!=null">
and gender = #{gender}
</if>
<if test="begin!=null and end!=null">
and entrydate between #{begin} and #{end}
</if>
</where>
</select>
</mapper>
@Test
void selectByCondition(){
List<Emp> emps = empMapper.selectByCondition("张", (short) 1,
LocalDate.of(2010, 1, 1),
LocalDate.of(2030, 1, 1));
System.out.println(emps);
}