Javaweb
发表于:2024-03-12 |

JavaWeb

前端

vue

vue是一套前端框架,免除原生JavaScript中的DOM操作,简化书写。

基于MVVM(Model-View-ViewModel)思想,实现数据的双向绑定,将编程的关注点放在数据上

框架:是一个半成品软件,是一套课重用的、通用的、软件基础代码模型,基于框架进行开发,更加快捷、更加高效。

  • Model: 数据模型,特指前端中通过请求从后台获取的数据
  • View: 视图,用于展示数据的页面,可以理解成我们的html+css搭建的页面,但是没有数据
  • ViewModel: 数据绑定到视图,负责将数据(Model)通过JavaScript的DOM技术,将数据展 示到视图(View)上

官网

Vue快速入门

  • 新建HTML页面,引入Vue.js文件
1
2
<script src="js/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> //vue2框架
  • 在JS代码区域,创建Vue核心对象,定义数据模型
1
2
3
4
5
6
7
8
<script>
new Vue({
el: "#app",
data:{
message: "Hello Vue!"
}
})
</script>
  • 编写视图
1
2
3
4
<div>
<input type="text" v-model="message">
{{ message }}
</div>

插值表达式

形式:

内容:可以是变量三元运算符函数调用算术运算

常用指令

指令:HTML标签上带有 v- 前缀的特殊属性,不同指令具有不同的含义。

常用指令如下:

指令 作用
v-bind 为HTML标签绑定属性,如设置href,css样式等
v-model 在表单元素上创建双向数据绑定
v-on 为HTML标签绑定事件
v-if 条件性的渲染某元素,判定为true时渲染,否则不渲染
v-else-if 条件性的渲染某元素,判定为true时渲染,否则不渲染
v-else 条件性的渲染某元素,判定为true时渲染,否则不渲染
v-show 根据条件展示某元素,区别在于切换的是display属性的值
v-for 列表渲染,遍历容器的元素或者对象的属性
  • v-bind
1
2
<a v-bind:href="url">传智教育</a>
<a :href="url">传智教育</a>
  • v-model
1
<input type="text" v-model="url">

注意:通过v-bind或者v-model绑定的变量,必须在数据模型中声明

  • v-on
1
<input type="button" value="按钮" v-on:click="handle()">
1
<input type="button" value="按钮" @click="handle()">
1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
new Vue({
el: "#app";
data{
...
},
methods:{
handle:function(){
alert('我被点击了');
}
},
})
</script>
  • v-if
1
2
3
4
年龄{{age}},经判定为:
<span v-if="age <= 35">年轻人</span>
<span v-else-if="age >35 && age < 60">中年人</span>
<span v-else>老年人</span>
  • v-show
1
2
年龄{{age}},经判定为:
<span v-show="age <= 35">年轻人</span>
  • v-for
1
<div v-for="addr in addrs">{{addr}}</div>
1
<div v-for="(addr,index) in addrs">{{index+1}} : {{addr}}</div>
1
2
3
4
data:{
...
addrs: ['北京','上海','广州','深圳','成都','杭州']
},

生命周期

  • 生命周期:指一个对象从创建到销毁的整个过程
  • 生命周期的八个阶段:每触发一个生命周期事件,会自动执行一个生命周期方法(钩子)
状态 阶段周期
beforeCreate 创建前
created 创建后
beforeMount 挂载前
mounted 挂载完成
beforeUpdate 更新前
updated 更新后
boforeDestory 销毁前
destoryed 销毁后

![1](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (1).png))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
new Vue({
el: "#app",
data: {

},
mounted(){
console.log("Vue挂载完毕,发送请求获取数据");
},
methods:{

},
})
</script>
  • mounted:装载完成,Vue初始化完成,HTML页面渲染成功。(发送请求到服务端,加载数据)

Ajax

  • 概念:Asynchronous JavaScript And XML ,异步的JavaScript和XML
  • 作用
    • 数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据
    • 异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户是否可用的校验等等
同步与异步
  • 同步

同步请求发送过程如下图所示:

![2](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (2).png)

浏览器页面在发送请求给服务器,在服务器处理请求的过程中,浏览器页面不能做其他的操作。只 能等到服务器响应结束后才能,浏览器页面才能继续做其他的操作。

  • 异步

异步请求发送过程如下图所示:

![3](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (3).png)

浏览器页面发送请求给服务器,在服务器处理请求的过程中,浏览器页面还可以做其他的操作。

原生Ajax

1.准备数据地址:https://yapi.smart-xwork.cn/mock/169327/emp/list

2.创建XMLHttpRequest对象:用于和服务器交换数据

3.向服务器发送请求

4.获取服务器响应数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1. 创建XMLHttpRequest
var xmlHttpRequest = new XMLHttpRequest();
//2. 发送异步请求
xmlHttpRequest.open('GET','https://mock.apifox.cn/m1/3128855-0-default/emp/list');
xmlHttpRequest.send();//发送请求
//3. 获取服务响应数据
xmlHttpRequest.onreadystatechange = function(){
//此处判断 4表示浏览器已经完全接受到Ajax请求得到的响应, 200表示这是
一个正确的Http请求,没有错误
if(xmlHttpRequest.readyState == 4 && xmlHttpRequest.status ==
200){
document.getElementById('div1').innerHTML =
xmlHttpRequest.responseText;
}
}

Axios

1.引入Axios的js文件

1
<script src="js/axios-0.18.0.js"></script>

2.使用Axios发送请求,并获取响应结果

  • get请求
1
2
3
4
5
6
7
axios({
method:"get",
url:"http://localhost:8080/ajax-demo1/aJAXDemo1?
username=zhangsan"
}).then(function (resp){
alert(resp.data);
})
  • post请求
1
2
3
4
5
6
7
8
axios({
method:"post",
url:"http://localhost:8080/ajax-demo1/aJAXDemo1",
data:"username=zhangsan"
}).then(function (resp){
alert(resp.data);
});

axios()是用来发送异步请求的,小括号中使用 js的JSON对象传递请求相关的参数:

  • method属性:用来设置请求方式的。取值为 get 或者 post。

  • url属性:用来书写请求的资源路径。如果是 get 请求,需要将请求参数拼接到路径的后面,格式为: url?参数名=参数值&参数名2=参数值2。

  • data属性:作为请求体被发送的数据。也就是说如果是 post 请求的话,数据需要作为 data 属性的值。

  • then() 需要传递一个匿名函数。我们将 then()中传递的匿名函数称为 回调函数,意思是该匿名函数在发送请求时不会被调用,而是在成功响应后调用的函数。而该回调函数中的 resp 参数 是对响应的数据进行封装的对象,通过 resp.data 可以获取到响应的数据。

Axios还针对不同的请求,提供了别名方式的api,具体如下:

方法名 描述
axios.get(url[,config]) 发送get请求
axios.delete(url[,config]) 发送delete请求
axios.post(url[,data[,config]]) 发送post请求
axios.put(url[,data[,config]]) 发送put请求

前端工程化

前后端分离

具体开发一个功能的步骤:

  1. 需求分析:首先我们需要阅读需求文档,分析需求,理解需求。
  2. 接口定义:查询接口文档中关于需求的接口的定义,包括地址,参数,响应数据类型等等
  3. 前后台并行开发:各自按照接口文档进行开发,实现需求
  4. 测试:前后台开发完了,各自按照接口文档进行测试
  5. 前后段联调测试:前段工程请求后端工程,测试功能
Vue项目

创建

命令行:vue create vue-project01

图形化界面:vue ui

![4](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (4).png)

Element

Element:是饿了么团队研发的,一套为开发者、设计者和产品经理准备的基于Vue2.0的桌面端组件库

组件:组成网页的部件,例如 超链接、按钮、图片、表格、表单、分页条等

  • 安装ElementUI组件库(在当前工程的目录下),在命令行执行指令:
1
npm install element -ui@2.15.3
  • 引入ElementUI组件库
1
2
3
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
  • 访问官网,复制组件代码,调整

shift+alt+f 代码对齐格式

Vue项目中使用Axios:

  1. 在项目目录下安装axios:npm install axios;
  2. 需要使用axios时,导入axios:import axios from ‘axios’;

Vue路由

前端路由:URL中的hash(#号)与组件之间的对应关系。

Vue Router

Vue Router是Vue的官方路由

组成:

其工作原理如下图所示:

![5](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (5).png)

  1. 首先VueRouter根据我们配置的url的hash片段和路由的组件关系去维护一张路由表;
  2. 然后我们页面提供一个组件,用户点击,发出路由请求;
  3. 接着我们的VueRouter根据路由请求,在路由表中找到对应的vue组件;
  4. 最后VueRouter会切换中的组件,从而进行视图的更新
  • 安装(创建Vue项目时已选择)
1
npm install vue-router@3.5.1
  • 定义路由

打包部署

  • 打包

![6](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (6).png)

  • 部署

nginx: Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。 其特点是占有内存少,并发能力强,在各大型互联网公司都有非常广泛的使用。 niginx在windows中的安装是比较方便的,直接解压即可。如下图所示就是nginx的解压目录以及目录结构说明:

![7](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (7).png)

将我们之前打包的前端工程dist目录下得内容拷贝到nginx的html目录下

然后我们通过双击nginx下得nginx.exe文件来启动nginx,nginx服务器的端口号是80,所以启动成功之后,我们浏览器直接访问http://localhost:80 即 可,其中80端口可以省略,其到此,我们的前端工程发布成功。 PS: 如果80端口被占用,我们需要通过conf/nginx.conf配置文件来修改端口号。如下图所示:

![8](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (8).png)

后端

Maven

Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具

作用:

  1. 依赖管理:方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题
  2. 统一项目结构:提供标准、统一的项目结构
  3. 项目构建:标准跨平台(Linux、Windows、MacOS)的自动化项目构建方式

仓库:用于存储资源,管理各种jar包

  • 本地仓库:自己计算机上的一个目录
  • 中央仓库:由Maven团队维护的全球唯一性的仓库,仓库地址为:https://repo1.maven.org/maven2/
  • 远程仓库(私服):一般由公司团队搭建的私有仓库

安装步骤:

  1. 解压apache-maven-3.6.1-bin.zip
  2. 配置本地仓库:修改conf/settings.xml中的为一个指定目录
1
<localRepository>D:\delvelop\apache-maven-3.6.1\mvn_repo</localRepository>
  1. 配置阿里云私服:修改conf/settings.xml中的标签,为其添加如下子标签:
1
2
3
4
5
6
<mirrors>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<mirrorOf>central</mirrorOf>
</mirrors>
  1. 配置环境变量:MAVEN_HOME为maven的解压缩目录,并将其bin目录加入PATH环境变量

配置Maven环境(当前工程)

  • 选择IDEA中 File –> Settings –> Build,Execution,Deployment –> Build Tools –> Maven
  • 设置IDEA使用本地安装的Maven,并修改配置文件及本地仓库路径

配置Maven环境(全局)

  • 直接在创建项目栏按上述操作即可,不必打开项目

  • 选择IDEA中 File –> Settings –> Build,Execution,Deployment –> Build Tools –> Maven

  • 设置IDEA使用本地安装的Maven,并修改配置文件及本地仓库路径

IDEA创建Maven项目

  1. 创建模板,选择Maven,点击Next
  2. 填写模块名称,坐标信息,点击finish,创建完成
  3. 编写HelloWorld,并运行

Maven坐标

  • Maven中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置
  • 使用坐标来定义项目或者引入项目中需要的依赖

Maven坐标主要组成

  • groupId:定义当前Maven项目隶属组织名称(通常是域名反写,例如:com.ithema)
  • artifactId:定义当前Maven项目名称(通常是模块名称,例如:order-service,goods-services)
  • version:定义当前项目版本号
1
2
3
<groupId>com.ithema</groupId>
<artifactId>maven-project01</artifactId>
<version>1.0-SNAPSHOT</version>
1
2
3
4
5
<dependency>
<groupId>cn.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>

导入Maven项目

方式一:打开IDEA,选择右侧Maven面板,点击+号,选中对应项目的pom.xml文件,双击即可

方式二:File => Project Structure => Modules => + => Import Module

依赖管理

  • 依赖:指当前项目运行所需的jar包,一个项目可以引用多个依赖
  • 配置:
    1. 在pom.xml中编写标签
    2. 标签中使用引入坐标
    3. 定义坐标的groupId、artifacId、version
    4. 点击刷新按钮,引入最新加入的坐标
1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>cn.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>

注意事项:

  • 如果引入的依赖,在本地仓库不存在,将会连接远程仓库/中央仓库,然后下载依赖。(这个过程会比较耗时,需要耐心等待)
  • 如果不知道依赖的坐标信息,可以到https://mvnrepository.com/中搜索

依赖传递

依赖具有传递性

  • 直接依赖:在当前项目中通过依赖配置建立的依赖关系

  • 间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源

  • 排除依赖:排除依赖指主动断开依赖的资源,被排除的资源无需指定版本,通过添加标签来排除依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
< !-- 排除依赖 -->
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven-projectB</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 排除依赖-->
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>

依赖范围

依赖的jar包,默认情况下,可以在任何地方使用,可以通过<scope>...</scope>设置其作用范围。

作用范围:

  • 主程序范围有效。(main文件夹范围内)
  • 测试程序范围有效。(test文件夹范围内)
  • 是否参与打包运行。(package指令范围内)
1
2
3
4
5
6
 <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
scope值 主程序 测试程序 打包(运行) 范例
compile(默认值) Y Y Y log4j
test - Y - junit
provided Y Y - servlet-api
runtime - Y Y jdbc驱动

生命周期

Maven的生命周期就是为了对所有的maven项目构建过程进行抽象和统一

Maven中有3套相互独立的生命周期:

  • clean:清理工作
  • default:核心工作,如:编译、测试、打包、安装、部署等
  • site:生成报告、发布站点等

每套生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。

![9](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (9).png)

我们看到这三套生命周期,里面有很多很多的阶段,这么多生命周期阶段,其实常用的并不多,主要关注以下几个:

  • clean:移除上一次构建生成的文件
  • compile:编译项目源代码
  • test:使用合适的单元测试框架运行测试(junit)
  • package:将编译后的文件打包,如:jar、war等
  • install:安装项目到本地仓库

注意事项:在同一套生命周期中,当运行后面的阶段时,前面的阶段也会运行。

执行指定生命周期的两种方式:

  • 在idea中,右侧的maven工具栏,选中对应的生命周期,双击执行
  • 在命令行执行时,通过命令执行
1
2
3
4
5
mvn clean
mvn compile
mvn package
mvn test
...

Web入门

Spring

官网:spring.io

Spring发展到今天已经形成了一种生态开发生态圈,Sring提供了若干个子项目,每个项目用于完成特定的功能

SpringBootWeb快速入门

需求:使用SpringBoot开发一个web应用,浏览器发起请求/hello后,给浏览器返回字符串”Hello World ~”

步骤:

  1. 创建springboot工程,并勾选web开发相关依赖
  2. 定义HelloController类,添加方法Hello,并添加注解
  3. 运行测试

创建请求处理类HelloController,添加请求处理方法Hello,并添加注解

![10](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (10).png)

运行启动类,打开浏览器测试

1
localhost:8080/hello

HTTP协议

概念:Hyper Text Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间数据传输的规则

特点:

  • 基于TCP协议:面向连接、安全
  • 基于请求-响应模型的:一次请求对应一次响应
  • HTTP协议是无状态的协议:对于事务处理没有记忆能力,每次请求-响应都是独立的
    • 优点:速度快
    • 缺点:多次请求间不能共享数据
请求协议

请求数据格式

请求行:请求数据第一行(请求方式、资源路径、协议)

请求头:第二行开始,格式:key - value

Host 请求的主机名
User-Agent 浏览器版本,例如Chrome浏览器的标示类似Mozilla/5.0…Chrome/79,IE浏览器的标示类似Mozilla/5.0(Windows NT …) like Gecko(考虑浏览器兼容问题
Accept 表示浏览器能接收的资源类型,如text/*,image/或者/*表示所有
Accept-Language 表示浏览器偏好的语言,服务器可以根据此返回不同语言的网页
Accept-Encoding 表示浏览器可以支持的压缩类型,例如gzip、deflate等
Content-Type 请求主体的数据类型
Content-Length 请求主体的大小(单位:字节)

请求体:POST请求,存放请求参数

请求方式-GET:请求参数在请求行中,没有请求体,如/brand/findAll?name=OPPO&status=1。GET请求是有大小限制的

请求方式-POST:请求参数在请求体中,POST请求是没有大小限制的

响应协议

响应行:响应数据第一行(协议、状态码、描述)

响应头:从第二行开始,格式为 key : value

响应体:最后一部分,存放响应数据

HTTP响应格式

1xx 响应中-临时状态码,表示请求已经接收,告诉客户端应该继续请求或者如果它已经完成则忽略它
2xx 成功-表示请求已经被成功接收,处理已完成
3xx 重定向-重定向到其他地方:让客户端再发起一次请求以完成整个处理
4xx 客户端错误-处理发生错误,责任在客户端,如:请求了不存在的资源、客户端未授权、禁止访问等
5xx 服务器错误-处理发生错误,责任在服务端,如:程序抛出异常等
Contenet-Type 表示该响应内容的类型,例如text/html,application/json
Content-Length 表示该响应内容的长度(即字节)
Content-Encoding 表示该响应压缩算法,例如gzip
Cache-Control 提示客户端如何缓存,例如max-age=300表示可以最多缓存300秒
Set-Cookie 告诉浏览器为当前页面所在的域设置Cookie

常见的响应状态码

状态码 英文描述 解释
==200== OK 客户端请求成功,即处理成功,这是我们最想看到的状态码
302 Found 指示所请求的资源已移动到由Location响应头给定的 URL,浏览器会自动重新访问到这个页面
304 Not Modified 告诉客户端,你请求的资源至上次取得后,服务端并未更改,你直接用你本地缓存吧。隐式重定向
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
403 Forbidden 服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源
==404== Not Found 请求资源不存在,一般是URL输入有误,或者网站资源被删除了
405 Method Not Allowed 请求方式有误,比如应该用GET请求方式的资源,用了POST
428 Precondition Required 服务器要求有条件的请求,告诉客户端要想访问该资源,必须携带特定的请求头
429 Too Many Requests 指示用户在给定时间内发送了太多请求(“限速”),配合 Retry-After(多长时间后可以请求)响应头一起使用
431 Request Header Fields Too Large 请求头太大,服务器不愿意处理请求,因为它的头部字段太大。请求可以在减少请求头域的大小后重新提交。
==500== Internal Server Error 服务器发生不可预期的错误。服务器出异常了,赶紧看日志去吧
503 Service Unavailable 服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好

状态码大全:https://cloud.tencent.com/developer/chapter/13553

Web服务器-Tomcat

Web服务器是一个软件程序,对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更加便捷。主要功能是“提供网上信息浏览服务”。

Tomcat是Apache软件基金会的一个核心项目,是一个开源免费的轻量级web服务器,支持Servlet/JSP少量JavaEE规范

JavaEE:java Enterprise Edition,java企业版。指java企业级开发的技术规范总和,包含13项技术规范:JDBC、JNDI、EJB、RMI、JSP、Servlet、XML、JMS、java IDL 、JTS、JTA、javaMall、JAF

Tomcat也被称为Web容器、Servlet容器,Servlet程序需要依赖于Tomcat才能运行

官网:https://tomcat.apache.org/

Tomcat的基本使用:

控制台中文乱码:修改conf/logging.properties

1
2
3
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
java.util.logging.ConsoleHandler.encoding = GBK //UTF-8 改为GBK
  • 关闭:
    • 直接x掉运行窗口:强制关闭
    • bin\shutdown.bat:正常关闭
    • Ctrl+C:正常关闭
  • 配置Tomcat端口号(conf/server.xml)
1
2
3
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
  • Tomcat部署项目

将项目放置到webapps目录下,即部署完成

常见问题:

  • 启动窗口一闪而过:检查JAVA_HOME环境变量是否正确配置
  • 端口号冲突:找到对应程序,将其关闭掉

注意事项:HTTP协议默认端口号为80,如果将Tomcat端口号改为80,则将来访问Tomcat时,不需要输入端口号

起步依赖:

基于Springboot开发的web应用程序,内置了tomcat服务器,当启动类运行时,会自动启动内嵌的tomcat服务器

请求响应

  • 请求(HttpServletRequest):获取请求数据
  • 响应(HttpServletResponse):设置响应数据
  • BS架构:Brower/Server,浏览器 / 服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。(维护方便 体验一般)
  • CS架构:Client / Server,客户端 / 服务器架构模式。(开发、维护麻烦、体验不错)

请求

Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。

作用:常用于进行接口测试

简单参数

简单参数:参数名与形参变量名相同,定义形参即可接收参数

如果方法形参名称与请求参数名称不匹配,可以使用@RequestParam完成映射

1
2
3
4
5
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name")String username,Integer age){
System.out.println(username+" : "+age);
return "OK";
}

注意事项:@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递则报错。如果该参数是可选的,可以将required属性设置为false

  • 原始方式

在原始的web程序中,获取请求参数,需要通过HttpServletRequest对象手动获取。

1
2
3
4
5
6
7
8
@RequestMapping("/simpleParam")
public String simpleParam(HttpServletRequest request){
String name = request.getParameter("name");
String ageStr = request.getParameter("age");
int age = Integer.parseInt(ageStr);
System.out.println(name+" : "+age);
return "OK";
}

实体参数

简单实体对象:请求参数名与形参名对象属性名相同,定义POJO接收即可

1
2
3
4
5
6
7
8
9
10
@RequestMapping("/simplePoJo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}

public class User{
private String name;
private Integer age;
}

复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping("/simplePoJo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}

public class User{
private String name;
private Integer age;
private Address address;
}

public Address{
private String province;
private String city;
}

数组集合参数

数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数

  • 数组接收:请求参数名与形参中数组变量名相同,可以直接使用数组封装
1
2
3
4
5
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println("Arrays.toString(hobby)");
return "OK";
}
  • 集合接收:请求参数名与形参中集合变量名相同,通过@RequestParam绑定参数关系
1
2
3
4
5
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "Ok";
}

日期参数

日期参数:使用@DateTimeFormat注解完成日期格式参数转换

1
2
3
4
5
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")LocalDateTime updateTime){
System.out.println(updateTime);
return "OK";
}

JSON参数

JSON参数:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用@RequestBody标识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}

public class User{
private String name;
private Integer age;
private Address address;
}

public Address{
private String province;
private String city;
}

路径参数

路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数

1
2
3
4
5
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id){
System.out.println(id);
return "OK";
}

获取多个路径参数

1
2
3
4
5
6
@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable Integer id , @PathVariable String name){
System.out.println(id);
System.out.println(name);
return "OK";
}

响应

ResponseBody

  • 类型:方法注解、类注解
  • 位置:Controller方法上 / 类上
  • 作用:将方法返回值直接响应,如果返回值类型是 实体对象 / 集合,将会转换为JSON格式响应
  • 说明:@RestController = @Controller + @ResonseBody

响应-字符串

1
2
3
4
5
@RequestMapping("/hello")
public String hello(){
System.out.println("Hello World ~");
return "Hello World ~";
}

响应-JSON对象

1
2
3
4
5
6
7
@RequestMapping("/getAddr")
public Address getAddr(){
Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");
return addr;
}

响应-JSON集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping("/listAddr")
public List<Address> listAddr(){
List<Address> list = new ArrayList<>();

Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");

Address addr2 = new Address();
addr2.setProvince("陕西");
addr2.setCity("西安");

list.add(addr);
list.add(addr2);
return list;
}

统一响应结果

Result(code、msg、data)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Result {
private Integer code ;//1 成功 , 0 失败
private String msg; //提示信息
private Object data; //数据 date
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@RequestMapping("/hello")
public Result hello(){
System.out.println("Hello World ~");
//return new Result(1,"success","Hello World ~");
return Result.success("Hello World ~");
}

@RequestMapping("/getAddr")
public Result getAddr(){
Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");
return Result.success(addr);
}

@RequestMapping("/listAddr")
public Result listAddr(){
List<Address> list = new ArrayList<>();

Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");

Address addr2 = new Address();
addr2.setProvince("陕西");
addr2.setCity("西安");

list.add(addr);
list.add(addr2);
return Result.success(list);
}
}

Springboot项目的静态资源(html、css、js等前端资源)默认存放目录为:classpath:/static,classpath:/public,classpath:/resources

分层解耦

三层架构

  • controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
  • service:业务逻辑层,处理具体的业务逻辑。
  • dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。

按员工案例拆分成三层架构后如下:

  • controller层:接收请求,响应数据
1
2
3
4
5
6
7
8
9
10
11
@RestController
public class EmpController {
private EmpService empService = new EmpServiceA();
@RequestMapping("/listEmp")
public Result list() throws URISyntaxException {
//调用service,获取数据
List<Emp> empList = empService.listEmp();
//3. 响应数据
return Result.success(empList);
}
}
  • dao层:数据访问操作
1
2
3
4
5
6
7
8
9
10
11
12
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() throws URISyntaxException {
//1. 加载并解析emp.xml
// String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
// 含有中文目录改成下面这个代码
String file = this.getClass().getClassLoader().getResource("emp.xml").toURI().getPath();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
  • service层:业务逻辑处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class EmpServiceA implements EmpService {
private EmpDao empDao = new EmpDaoA();
@Override
public List<Emp> listEmp() throws URISyntaxException {

//1.调用dao,获取数据
List<Emp> empList = null;
try {
empList = empDao.listEmp();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
//2. 对数据进行转换处理 - gender, job
empList.stream().forEach(emp -> {
//处理 gender 1: 男, 2: 女
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
}else if("2".equals(gender)){
emp.setGender("女");
}

//处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
}else if("2".equals(job)){
emp.setJob("班主任");
}else if("3".equals(job)){
emp.setJob("就业指导");
}
});
return empList;
}
}

分层解耦

  • 内聚:软件中各个功能模块内部的功能联系。
  • 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
  • 软件设计原则:高内聚低耦合

控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

依赖注入:Dependency Injection,简称DI。容器为应用程序提供运行时所依赖的资源,称之为依赖注入。

Bean对象:IOC容器中创建、管理的对象,称之为bean

IOC & DI 入门

  1. Service层 及 Dao层的实现类,交给IOC容器管理。– 加上@Component
  2. 为Controller及Service注入运行时依赖的对象。 – 在成员变量前面加上@Autowired
  3. 运行测试。
  • Dao层
1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() throws URISyntaxException {
//1. 加载并解析emp.xml
// String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
// 含有中文目录改成下面这个代码
String file = this.getClass().getClassLoader().getResource("emp.xml").toURI().getPath();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
  • Service层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Component
public class EmpServiceA implements EmpService {
@Autowired
private EmpDao empDao;
@Override
public List<Emp> listEmp() throws URISyntaxException {

//1.调用dao,获取数据
List<Emp> empList = null;
try {
empList = empDao.listEmp();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
//2. 对数据进行转换处理 - gender, job
empList.stream().forEach(emp -> {
//处理 gender 1: 男, 2: 女
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
}else if("2".equals(gender)){
emp.setGender("女");
}

//处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
}else if("2".equals(job)){
emp.setJob("班主任");
}else if("3".equals(job)){
emp.setJob("就业指导");
}
});
return empList;
}
}
  • Controller层
1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
public class EmpController {
@Autowired
private EmpService empService;
@RequestMapping("/listEmp")
public Result list() throws URISyntaxException {
//调用Dao层,查询数据
List<Emp> empList = empService.listEmp();
//3. 响应数据
return Result.success(empList);
}
}

若需要使用其他接口的实现类,则只需要将当前使用的接口实现类中的@Component注释掉即可

IOC详解

Bean的声明

要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:

注解 说明 位置
@Component 声明bean对象的基础注解 不属于以下三类时,用此注解
@Controller @Component的衍生注解 标注在控制器类上
@Service @Component的衍生注解 标注在业务上
@Repository @Component的衍生注解 标注在数据访问类上(由于与mybatis整合,用的少)

注意事项:

  • 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
  • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller

Bean组件扫描

  • 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。
  • @ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包。

如果其中一个包未放在启动包下面,则可以通过以下方法解决:

  • 手动添加@ComponentScan注解,指定要扫描的包 (==仅做了解,不推荐==)
1
2
//添加以下注解
@Component({"包名1","包名2"})
  • 将我们定义的controller,service,dao这些包都放在引导类所在包com.itheima的子包下,这样我们定义的bean就会被自动的扫描到

DI详解

依赖注入,是指IOC容器要为应用程序去提供运行时所依赖的资源,而资源指的就是对象。

@Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报错,以下是几种解决方案

  1. @Primary设定优先级
1
2
3
4
5
@Primary
@Service
public class EmpServiceA implements EmpService{

}
  1. @Qualifier配合@Autowired使用(@Antowiredf + @Qulifier(“bean的名称”))
1
2
3
4
5
6
@RestController
public class EmpController{
@Autowired
@Qualifier("empServiceA")
private EmpService empService;
}
  1. 使用@Resource(@Resource(name = “bean的名称”))
1
2
3
4
5
@RestController
public class EmpController{
@Resource(name = "empServiceB")
private EmpService empService;
}

@Resource和@Autowired区别

  • @Autowired是springboot框架提供的注解,而@Resource是JDK提供的注解。
  • @Autowired默认是按照类型注入,而@Resource默认是按照名称注入。

MyBatis

MyBatis是一款优秀的持久层框架,用于简化JDBC的开发。

MyBaits本是Apache的一个开源项目iBatis,2010年该项目由Apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。

官网:https://mybatis.org/mybatis-3/zh/index.html

入门

案例:使用mybatis查询所有用户数据

  1. 准备工作(创建springboot工程,数据库表user,实体类user)
  2. 引入Mybatis的相关依赖,配置Mybatis
  3. 编写SQL语句(注解/XML)
JDBC

JDBC:(Java Database Connectivity),就是使用Java语言操作关系模型数据库的一套API。

本质:

  • sun公司官方定义的一套操作所有关系型数据库的规范,即接口。
  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包
  • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Test
public void testJdbc() throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");

//2.获取连接对象
String url = "jdbc:mysql://localhost:3306/mybaits";
String username = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url,username,password);

//3.获取执行SQL的对象Statement,执行SQL语句,返回结果
String sql = "select * from user";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);

//4.封装结果数据
List<User> userList = new ArrayList<>();
while(resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getNString("name");
Short age = resultSet.getShort("age");
Short gender = resultSet.getShort("gender");
String phone = resultSet.getString("phone");
User user = new User(id,name,age,gender,phone);
userList.add(user);
}

//5.释放资源
statement.close();
connection.close();
userList.forEach(user->{
System.out.println(user);
});
}
数据库连接池

数据库连接池,是个容器,负责分配、管理数据库连接(Connection),它允许应用程序重复使用一个现有的数据库连接,而不是重新再建立一个,释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接泄漏

优势

  • 资源重用
  • 提升系统响应速度
  • 避免数据库连接泄漏

标准接口:DataSource

  • 官方(sun)提供的数据库连接池接口,由第三方组织实现此接口。
  • 功能:获取连接 connection getConnection() throws SQLException;

常见产品:C3P0、DBCP、Druid、Hikari(springboot默认)

Druid(德鲁伊)

  • Druid连接池是阿里巴巴开源的数据库连接池项目
  • 功能强大、性能优秀、是Java语言最好的数据库连接池之一

切换Druid数据库连接池

官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

1
2
3
4
5
6
<!-- 添加到pom.xml文件-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactld>druid-spring-boot-starter</artifactld>
<version>1.2.8</version>
</dependcy>
1
2
3
4
5
#添加到application.properties文件中
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql//localhost:3306/mybatis
spring.datasource.username=root
spring.datasource.password=123456
lombok

Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter / setter、equals、hashcode、toString等方法,并可以自动化成日志变量,简化Java开发、提高效率。

注解 作用
@Getter / @Setter 为所有属性提供get/set方法
@ToString 会给类自动生成易阅读的toString方法
@EqualsAndHashCode 根据类所拥有的非静态字段自动重写equals方法和hashCode方法
@Data 提供了更综合的生成代码的功(@Getter+@Setter+@ToString+@EqualsAndHashCode)
@NoArgsConstructor 为实体类生成无参的构造器方法
@AllArgsConstructor 为实体类生成除了static修饰的字段之外带有各参数的构造器方法。

使用lombokl需要引入依赖

1
2
3
4
<dependency>
<grouId>org.projectlombok</grouId>
<artifactld>lombok</artifactld>
</dependency>

注意事项:Lombok会在编译时,自动生成对应的java代码,我们使用lombok时,还需要安装一个lombok的插件(idea自带)

基础操作

案例:根据提供的《tlias智能学习辅助系统》页面原型及需求,完成员工管理的需求开发。

功能列表:

  • 查询(根据主键ID查询、条件查询)
  • 新增
  • 更新
  • 删除(根据主键ID删除,根据主键ID批量删除)

准备工作

  • 准备数据库表emp
  • 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
  • application.properties中引入数据库连接信息
  • 创建对应的实体类Emp(实体类属性采用驼峰命名)
  • 准备Mapper接口EmpMapper
根据主键删除ID

SQL语句

1
delete from emp where id = 17;

接口方法

1
2
@Delete("delete from emp where id = #{id}")
public void delete(Integer id);

注意事项:如果mapper接口方法形参只有一个普通类型的参数,#{…}里面的属性名可以随便写,如:#{id}、#{value}

日志删除

可以在application.properties中,打开mybatis日志,并指定输出到控制台

1
2
#指定mybatis输出日志的位置,输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.stdOutImpl

预编译SQL

![11](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (11).png)

预编译SQL优势:

  • 性能更高
  • 更安全(防止SQL注入)

SQL注入是指通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。

占位参数符

#{…}:执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值。使用时机:参数传递,都使用#{…}

${…}:直接将参数拼接在SQL语句中,存在SQL注入问题。使用时机:如果对表名、列表进行动态设置时使用。

新增员工
  • SQL语句
1
2
insert into emp (username, name, gender, image, job, entrydate, dept_id, create_time, update_time)
values ('Tom','汤姆','1','1.ipg',1,'2005-01-01',1,now(),now());
  • 接口方法
1
2
3
4
@Insert("insert into emp (username, name, gender, image, job, entrydate, dept_id, create_time, update_time)\n" +
"values (#{username},#{name},#{gender},#{image},#{job},#{entryDate},#{deptId},#{createTime},#{updateTime})")
public void insert(Emp emp);
//由于需要传入的数据比较多,因此我们采用传入一个实体对象的方式来实现

新增(主键返回)

描述:在数据添加成功后,需要获取插入数据库数据的主键,如添加套餐数据时,还需要维护套餐菜品关系表数据。

  • 实现
1
2
3
4
@Options(keyProperty="id",useGeneratedKeys=true)
@Insert("insert into emp (username, name, gender, image, job, entrydate, dept_id, create_time, update_time)\n" +
"values (#{username},#{name},#{gender},#{image},#{job},#{entryDate},#{deptId},#{createTime},#{updateTime})")
public void insert(Emp emp);
更新
  • SQL语句(根据ID更新员工信息)
1
2
update emp set username='songdaxia',name='宋大侠',gender='1',image='1.jpg',job='2',
entrydate='2020-01-01',dept_id='2',update_time='2022-01-01 22:43:21' where id = 1;
  • 接口方法
1
2
@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);
查询(根据ID查询)
  • SQL语句
1
select * from emp where id = 19;
  • 接口方法
1
2
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);

数据封装

  • 实体类属性名和数据表查询返回的字段名一致时,mybatis会自动封装。
  • 如果实体类属性名和数据表查询返回的字段名不一致时,不能自动封装。

解决方案:

  1. 起别名:在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样
1
2
3
4
5
//方案一:给字段起别名,让别名与实体类属性一致
@Select("select id,username,password,name,gender,image,job," +
"entrydate entryDate,dept_id deptId,create_time createTime,update_time updateTime " +
"from emp where id = #{id}")
public Emp getById(Integer id);
  1. 手动结果映射:通过@Results及@Result进行手动结果映射
1
2
3
4
5
6
7
8
9
//方案二:通过@Results,@Result注解手动映射封装
@Results({
@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime"),
@Result(column = "entrydate", property = "entryDate")
})
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
  1. 开启驼峰命名:如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射
1
2
#方案三:开启mybatis的驼峰命名自动映射开关  ---- a_cloumn    --------->  aColumn
mybatis.configuration.map-underscore-to-camel-case=true
查询(条件查询)
  • SQL语句
1
2
select * from emp where name like '%张%' and gender = 1 and entrydate between '2010-01-01' and '2020-01-01' order by
update_time desc;
  • 接口方法
1
2
3
 @Select("select * from emp where name like '%${name}%' and gender = #{gender} and entrydate between #{begin} and #{end} order by\n" +
"update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);

使用$会存在性能低、不安全、存在SQL注入问题,可以通过字符串拼接函数concat来解决这个为题

1
2
3
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by\n" +
"update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);

参数名说明

  • 在springboot的2.x版本

![14](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (14).png)

  • 在springboot的1.x版本 / 单独使用mybatis

![15](https://cdn.jsdelivr.net/gh/hnuyl16/images/javaweb (15).png)

XML映射文件

规范

  • XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置到相同包下(同名同包)
  • XML映射文件的namespace属性为Mapper接口全限定名一致
  • XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致
1
2
3
4
5
//Mapper接口
@Mapper
public interface EmpMapper{
public List<Emp> list(String name,short gender,LocalDate begin,LocalDate end);
}
1
2
3
4
5
6
7
<!-- XML映射文件-->
<mapper namespace="com.ithema.mapper.EmpMapper">
<select id="list" resultType="com.ithema.pojo.Emp">
select * from emp where name like concat('%',#{name},'%') and gender=#{gender}
and entrydate between #{begin} and #{end} order by update_time desc
</select>
</mapper>

MybatisX

MybatisX是一款基于IDEA的快速开发Mybatis的插件,为效率而生。

使用Mybatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句。

官方说明:https://mybatis.net.cn/getting-started.html

动态SQL

随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<select id="list" resultType="com.ithema.pojo.Emp">
select id,username,password,name,gender,image,job,entrydate,
dept_id,create_time,update_time from emp
where
<if test="name != null">
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>
order by update_time desc
</select>
  • :用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。
1
2
3
<if test=" name != null">
name like concat('%',#{name},'%')
</if>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 <select id="list" resultType="com.ithema.pojo.Emp">
select id,username,password,name,gender,image,job,entrydate,
dept_id,create_time,update_time from emp
where
<if test="name != null">
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>
order by update_time desc
</select>

引入标签

:where元素只会在子元素有内容的情况下才插入where语子句。而且会自动去除子句的开头的AND或OR。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 <select id="list" resultType="com.ithema.pojo.Emp">
select id,username,password,name,gender,image,job,entrydate,
dept_id,create_time,update_time from emp
<where>
<if test="name != null">
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>
order by update_time desc
</select>

动态更新修改员工信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 <update id="update2" >
# 动态更新员工信息
update emp
set
<if test="username != null">
username=#{username},
</if>
<if test="name != null">
name=#{name},
</if>
<if test="gender != null">
gender=#{gender},
</if>
<if test="job != null">
job=#{job},
</if>
<if test="entryDate != null">
entrydate=#{entryDate},
</if>
<if test="deptId != null">
dept_id=#{deptId},
</if>
<if test="updateTime != null">
update_time=#{updateTime}
</if>
where id = #{id}
</update>

:动态地在首行插入SET关键字,并会删除额外地逗号。(用在update语句中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 <update id="update2" >
# 动态更新员工信息
update emp
<set>
<if test="username != null">
username=#{username},
</if>
<if test="name != null">
name=#{name},
</if>
<if test="gender != null">
gender=#{gender},
</if>
<if test="job != null">
job=#{job},
</if>
<if test="entryDate != null">
entrydate=#{entryDate},
</if>
<if test="deptId != null">
dept_id=#{deptId},
</if>
<if test="updateTime != null">
update_time=#{updateTime}
</if>
</set>
where id = #{id}
</update>
  • SQL语句
1
delete from emp where id in(18,21,24);
  • 接口方法
1
public void deleteByIds(List<Integer> ids);
  • XML映射文件
1
2
3
4
5
6
<delete id="deleteByIds">
delete from where id in
<foreach collection="ids" item="id" separator="," open="(",close=")">
#{id}
</foreach>
</delete>

属性

  • collection:集合名称
  • item:集合遍历出来的元素 / 项
  • separator:每一次遍历使用的分割符
  • open:遍历开始前拼接的片段
  • close:遍历结束后拼接的片段

sql片段

1
2
3
4
<sql id="commonSelect">
select id,username,name,gender,image,job,entrydate,dept_id,
create_time,update_time from emp
</sql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  <select id="list" resultType="com.ithema.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name != null">
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>
order by update_time desc
</select>

<selecct id="getByIds" resultType="com.ithema.pojo.Emp">
<include refid="commonSelect"/>
where id = #{id}
</selecct>
  • :定义可重用的SQL片段
  • :通过属性refid,指定包含的sql片段
上一篇:
Python数据分析
下一篇:
MySQL