【学习笔记】SpringMVC+SpringMybatis 学习笔记

文章目录

SpringMVC

Axios入门案例

Ajax

局部刷新,异步访问。

同步:浏览器发起请求到服务器时,如果服务器没有响应,用户则无法获取页面数据,处于等待状态.不可以做其它的操作.

异步:异步请求时,浏览器可以进行其它的操作.当ajax数据获取之后,信息在页面的局部刷新. (可以理解为多线程操作方式)

Ajax为什么可以异步: 中间有Ajax引擎.
回调函数: 服务器返回数据,通过回调函数通知用户.

image-20220210112617188

常见Ajax API : jQuery/axios 让Ajax调用更简洁

SpringMVC

总结:
1.SpringMVC是Spring框架后续开发的web模块.主要负责与前端用户进行交互.
2.SpringMVC基于Servlet进行开发的框架,目的简化前后端的调用.

传统servlet的弊端(看看行了)

1.传统servlet 一个业务方法,需要编辑一个servlet。如果业务复杂就会导致servlet数量增多

2.servlet请求方式只能支持get和post请求

3.通过servlet获取参数的类型都是String类型,需要手动类型转换

4.如果编辑servlet需要编辑大量的web.xml文件

上述都是历史产物!后期SpringMVC将servlet进行了封装

框架之间的关系

image-20220215200840557

常用的注解!!

@Controller // 将该类先交给SpringMVC进行管理,之后将SpringMVC整体框架交给Spring管理
@RequestMapping("/hello") //该路径必须与用户访问路径一致.如果路径不一致,则会报404异常
@ResponseBody //表示该方法的返回值都是JASON字符串,如果返回值为String类型,则原数据返回

    

小demo

image-20220215201958760

image-20220215202005695

SpringMVC-简单参数传递

需求说明

常识:通过浏览器地址栏只能发起get请求

Url1:http://localhost:8080/findUserByid?id=123

难点:动态接收请求和参数id

image-20220215204402082

底层源码

image-20220215204855977

SpirngMVC为了简化取值过程,可以直接添加参数。简化后:

image-20220215205515833

结果:

image-20220215210312396

image-20220215210319566

知识点:

1.SpirngMVC为了简化取值过程,可以直接添加参数

2.SpirngMVC请求路径地址不能重复

3.如果遇到多个参数,则可以使用对象方式接收,对象属性必须添加get/set方法

SpringMVC如果发现参数名称对象属性名称一致时则自动调用set方法完成赋值

User对象接收信息,set方法赋值

image-20220215211949977

image-20220215212056615

image-20220215212116691

Json

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。它是基于 JavaScript Programming Language , Standard ECMA-262 3rd Edition - December 1999 的一个子集。 JSON采用完全独立于程序语言的文本格式,但是也使用了类C语言的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
根源: 网络传输协议http/https,本质传输的数据都是字符串/字节信息. 协议与系统无关. 所以采用JSON的方式将数据按照特定的顺序进行排列. JSON中的特殊的数据结构,可以很好的解析字符串.

小demo

image-20220219100424022

image-20220219100829809

image-20220219100847035注意:这边打印出来的值,是利用get方法打印出来的。getxx(),去掉get首字母小写当作key,方法返回值当作value

image-20220219101014075

Json

​ {“id”: “100”,“name”:“tomcat”,“age”:18,“sex”:“男”}

​ [1,2,3,4,“张三”,“李四”]

​ [1,2,true,false,{“id”:100,“name”:“tomcat”},[{arrays: [[],[],[]]},5,6]]、

MVC参数接收

image-20220221093537037

image-20220221094031494

image-20220221094039525

RestFul结构(难点)

传统get请求业务说明

需求:向后端服务器传递多个参数,

需求说明: 向后端服务器传递多个参数, name=tomcat, age=18,sex=男
URL地址: http://localhost:8080/getUser?name=tomcat&age=18&sex=男
该方法能否优化? 能否降低字节数量

RestFul参数拼接

语法: 省略key,将value使用/的方式进行分隔.并且位置固定.
URL地址: http://localhost:8080/getUser/tomcat/18/男

先修改URL地址

RestFul参数接收

image-20220221095352884

image-20220221100357612

优化:

如果restFul的属性名称与对象的属性名称一致,则可以利用对象接收

image-20220221103634827

RestFul请求路径的通用写法

例子:

  1. http://localhost:8080/getUserById?id=100
  2. http://localhost:8080/deleteUserById?id=100
  3. http://localhost:8080/updateUserById?id=100&name=tomcat
    1. http://localhost:8080/insertUser POST 提交

问题: 上述的操作 意图特别的明显. 对后期操作会带来不安全的风险.

优化: restFul风格的请求名称的要求,不能出现动词

http://localhost:8080/userById?id=100 类型: GET 查询业务逻辑
http://localhost:8080/userById?id=100 类型: Delete 删除业务逻辑
http://localhost:8080/userById?id=100&name=tomcat 类型: PUT 更新业务逻辑
http://localhost:8080/user 类型: POST 新增业务逻辑

请求类型的种类

常用4种:get/post/put/delete

img

注解总结

在这里插入图片描述
在这里插入图片描述
27. @PathVariable restful结构,接收参数的注解
28. @GetMapping(“”) 只能接收get请求类型
29. @DeleteMapping(“”)
30. @PostMapping(“”)
31. @PutMapping(“”)
32. @RestController 标识controller类 返回值为Jason
33. @Controller@ResponseBody结合体
34. @CrossOrigin //允许跨域访问
35. @Data //动态生成get/set/toString/equals/hashCode等方法
36. @Accessors(chain = true) //开启链式加载 重写set方法
37. @NoArgsConstructor //无参构造
38. @AllArgsConstructor //全参构造
39. @Mapper //将接口交给Spring容器管理 Map<userMapper,JDK代理对象>
40. @SpringBootTest 该注解的作用在进行代码测试时启动spring容器,之后动态的获取对象 注意包路径 主启动类的同包及子包中.
41. @Param mybatis中将参数封装为map集合
42. @Alias(“user”)mybatis定义别名
43. @MapperScan Mybatis中扫描指定包路径的接口 为其创建代理对象.
44. @Insert Mybatis 新增操作注解
45. @Update Mybatis 修改操作注解
46. @Delete Mybatis 删除操作注解
47. @Select Mybatis 查询操作注解
48. @Transactional//事务的注解
49.

前后端调用

demo

Axios入门案例
</head>
<body>
	<!-- 1导入js文件 -->
	<script src="js/axios.js"></script>
	<!-- 2编辑js代码 -->
	<script>
		// url地址:http://localhost:8080/findUser
		let url1="http://localhost:8080/axios/findUser";
		//(url地址,参数)
		
		axios.get(url1)  //发起ajax请求
			.then(function(promise){ //成功之后执行回调函数,promise是返回值对象
				console.log(promise.data)  //输出
			})
		
		// axios.get(url1);
		// 	.then(res=>{
				
		// 	})
		
	</script>
	<h1>学习Axios的ajax调用</h1>
</body>
package com.jt.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

//@Controller
//@ResponseBody
@RestController  //两个结合体
@CrossOrigin   //允许跨域访问
@RequestMapping("/axios")  //抽取公共部分
public class AxiosController {

    @RequestMapping("/findUser")
    public String findUser(){
        return "查询用户成功";
    }
}

前端网页:

axios用法

image-20220221144822121

浏览器F12用法

Network,(console)

image-20220221145444155

Axios-Get传参

参数拼接写法

多参数:axios.get(url2,{params:user1})

前端:

image-20220221160442456

后端:

image-20220221160504958

html结果:

image-20220221160725904

network可以查看执行内容

image-20220221160752106

restful传参

image-20220221184022956

image-20220221184035723

Axios-post请求

post请求语法 /* * 2. 需求: 一般业务新增时,采用post提交 * URL: http://localhost:8080/axios/saveUser * axios.post(url地址,js对象) * .then(回调函数!!!) */

image-20220222095137300

image-20220222095200382

关于常见请求类型语法说明

  1. GET/DELETE 语法相同
  2. POST/PUT 语法相同

Axios-put

image-20220222111353777

image-20220223084724645

关于跨域说明

同源策略

要素1: 浏览器的访问地址
要素2: Ajax的请求的网址
策略说明: 如果上述的要素同时满足 协议://域名:端口号都相同的情况,则称之为满足同源策略.可以进行正确的调用. 也称之为 “同域访问”.

什么是跨域

违反了同源策略就叫跨域访问

考题

案例1:

浏览器地址: http://www.jd.com/xx/xx
ajax地址: https://www.jd.com/yy/yy 跨域: 协议不同
案例2:

浏览器地址: http://www.jd.com/xx/xx
ajax地址: http://www.jd.com/yy/yy 同域请求
案例3:

浏览器地址: http://www.jd.com:80/xx/xx
ajax地址: http://www.jd.com/yy/yy 同域请求!!!
案例4:
前提: 域名与IP对应

浏览器地址: http://www.jd.com/xx/xx
ajax地址: http://8.8.8.8/yy/yy 跨域请求! 域名不一致
案例5:

浏览器地址: https://www.jd.com/xx/xx
ajax地址: https://www.jd.com:443/yy/yy 同域请求 https的默认端口号 443
案例6:

浏览器地址: http://www.jd.com/xx/yy/xx
ajax地址: http://miaoshi.jd.com/yy/yy 跨域请求 域名不同

*@CrossOrigin注解说明

image-20220222120731187

前端JS-回调地狱

说明: 如果Ajax嵌套的层级较多,则把这种结构称之为"回调地狱"
嵌套规则:

  1. 用户发起第一个Ajax请求.回调函数中的结果,要当做第二个ajax请求的参数.
  2. 用户第二个ajax回调函数的结果,要当做第三个Ajax请求的参数 以此类推!!!

image-20220223092258366

回调地狱问题说明:
由于回调方法和请求的方法在2行,导致嵌套的结构没有办法优化.如果需要优化,则应该将Ajax的请求一行搞定. 例如
let result1 = axios.get(url1);
let result2 = axios.get(url2,result1)
let result3 = axios.get(url3,result2)

解决方法

Axios入门案例
	<!-- 2.编辑JS代码 -->
	<script>
		/* let url1 = "http://localhost:8080/axios/findUser"
		axios.get(url1)
			 .then(function(promise){
				console.log(promise.data)
				
				axios.get("url2",promise.data)
					 .then(promise2 => {
						 console.log(promise2.data);
						 
						 axios.get("url3",promise2.data)
							  .then(promise3 => {
								  console.log(promise3.data)
								  //...嵌套十八层,比喻为回调地狱
							  })
					 })
			 }) */
			 
			 /**
			  * 语法: 
			  * 	1.async 关键字修饰函数
			  * 	2.await 关键字修改ajax请求
			  * 	3.先定义函数.之后调用函数
			  * 	语法说明: 解构赋值操作
			  */
			 async function getUser(){
				let url1 = "http://localhost:8080/axios/findUser"
				let {data: result} = await axios.get(url1)
				console.log(result)
				
				//let promise= let promise = await axios.get(url1)
				//console.log(promise.data)
				 //return promise
			 }
			 
			 //调用函数
			 getUser()
			 
			/* async function getUser2(data){
				 let url2 = "http://localhost:8080/axios/findUser"
				 let promise = await axios.get(url2,data)
				 return promise
			 }
			 
			 let result1 = getUser();
			 let result2 = getUser2(result1); */
			 
	</script>
	<h1>学习Axios的ajax调用</h1>
</body>

1、Mybatis

Mybatis介绍
官网地址: https://mybatis.org/mybatis-3/zh/index.html
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

总结:

  1. MyBatis 是一款优秀的持久层框架 在内部封装了JDBC,简化了操作数据库的过程.
  2. 映射: 数据库中的表 与POJO中的类一一映射.
    表中的字段与类中的属性一一映射

导入项目

1.编辑pom.xml文件

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>
    <!--jdbc依赖包-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!--添加lombok的包-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

2.将原src文件删除 后 copy一份新的

image-20220222143112234

lombok插件安装

1.lombok介绍
说明: pojo对象中必须添加get/set/toString等常规方法,但是该方法写起来繁琐,但是又必须添加. 所以可以引入lombok插件动态生成上述的方法.

2.导入jar包


org.projectlombok
lombok
3 安装lombok插件

3.搜索安装: lombok的插件

image-20220222153805537编辑pojo

image-20220222161526545

编辑Mapper接口

规则: 基于面向接口开发的规则,准备一个新的接口

image-20220222182344427

Spring整合Mybatis的配置

说明: Mybatis原生代码的结构混乱,比较复杂.所以采用Spring整合mybatis的操作.,简化开发的步骤.
其中表示spring整合mybatis的步骤 其中的配置信息暂时 了解即可.

<?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">
<!--
    调用流程:
         1.编辑Mapper接口 编辑接口方法
         2.映射文件与Mapper接口绑定 namespace
-->
<mapper namespace="com.jt.mapper.UserMapper">
    <!--标识使用二级缓存!!!-->
    <cache/>

    <!--
        1.id与接口的方法名称绑定
        2. 回顾:JDBC->resultSet->遍历结果集->手动封装对象
        3. resultType: mybatis自动的将结果集的数据封装为对象
                       如果返回值List集合,则自动封装为List,User充当其中的泛型对象
                       如果返回值User对象.则直接返回User对象
    -->
    <select id="findAll" resultType="com.jt.pojo.User">
        select * from demo_user
    </select>

    <!--根据id查询用户数据
        语法: 动态获取数据 #{属性名称}
        #号效果: 有预编译的效果  防止Sql注入攻击问题
                所以以后取值使用#号
    -->
    <select id="findUserById" resultType="com.jt.pojo.User">
        select * from demo_user where id= #{id}
    </select>

    <!--
        规则:
             1.如果接口方法中,int类型的返回值,则入库之后,mybatis自动回传数据
             2.如果接口中传递的是POJO对象.则通过#{属性}取值
        大小问题:
              1.windows系统中程序运行不区分大小写.
              2.Linux系统 严格区分大小写.
              3.程序猿口头禅:  我在我本机上没问题呀!!!!
    -->
    <insert id="saveUser">
        insert into demo_user(id,name,age,sex) values (null,#{name},#{age},#{sex})
    </insert>

    <update id="updateUser">
        update demo_user set age=#{age}, sex=#{sex}
        where name=#{name}
    </update>

    <delete id="deleteUser">
        delete from demo_user where name=#{name}
    </delete>

    <!--
        知识点1: 通过 #{参数名称/对象中的属性/Map中的key}
        知识点2: xml文件中有些字符需要转义
                > &gt;   < &lt;
                & &amp;
    -->
    <select id="findUserByAge" resultType="com.jt.pojo.User">
        select * from demo_user where age>#{minAge} and age &lt; #{maxAge}
    </select>

    <select id="findUserByAge2" resultType="com.jt.pojo.User">
        select * from demo_user where age>#{minAge} and age &lt; #{maxAge}
    </select>

    <!--Sql标签作用: 抽取公共的部分,可以被其它的Sql引用-->
    <sql id="findColumn">
        select id,name,age,sex from demo_user
    </sql>

    <select id="findByLike" resultType="User">
        <include refid="findColumn"/> where name like "%"#{key}"%"
    </select>

    <!--
        需求: Integer[] ids 中的数据一个一个取出来.拼接Sql
        知识点: mybatis中如何遍历数组
        foreach标签用法:
            1. collection:需要遍历的集合的类型
                1.1 数组类型  关键字:array
                1.2 list类型 关键字:list
                1.3 map类型  关键字:Map中的key
            2. open/close 循环开始和结束标签,一般自己写
            3. item 遍历数据的变量名称
            4. separator 参数之间的分隔符
    -->
    <select id="findInArray" resultType="User">
        select * from demo_user where id in (
        <foreach collection="list" item="id" separator=",">
            #{id}
        </foreach>
        )
    </select>

    <!--参数传递是Map集合,所以关键字使用key-ids1 -->
    <select id="findInMap" resultType="User">
        select * from demo_user where id in (
            <foreach collection="ids1" item="id" separator=",">
                #{id}
            </foreach>
            ,
            <foreach collection="ids2" item="id" separator=",">
                #{id}
            </foreach>
        )
    </select>

</mapper>

Spring的测试类

package com.jt;

import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest //该注解的作用启动spring容器中,之后动态的获取对象
public class TestMybatis {

    @Autowired  //IDEA编译异常 不影响代码的执行
    private UserMapper userMapper;

    @Test
    public void test01(){
        System.out.println(userMapper.getClass());
        List<User> userList = userMapper.findAll();
        System.out.println(userList);
    }
}

image-20220222190440613

image-20220223100212384

MybatisTest2-查找

1.测试函数

image-20220223104841364

2.接口中创建方法image-20220223104917259

3.xml文件中与接口中方法绑定 然后 写sql语句

image-20220223105035796

Test3-入库

image-20220223113648197image-20220223113705440

   <!--
     规则:
          1.如果接口方法中,int类型的返回值,则入库之后,mybatis自动回传数据
          2.如果接口中传递的是POJO对象.则通过#{属性}取值
     大小问题:
           1.windows系统中程序运行不区分大小写.
           2.Linux系统 严格区分大小写.
           3.程序猿口头禅:  我在我本机上没问题呀!!!!
 -->
   <insert id="saveUser1">
       insert into demo_user(id,age,name,sex) values(null,#{age},#{name},#{sex})
   </insert>

@param多个参数

说明: 根据下列的代码,不能非常直观去了解业务. 能否优化该操作.

List<User> findUserByAge(Map<String, Object> map);

image-20220223144248362

image-20220223144521749

//如果参数是多值,则需要封装为单值Map

//@Param将参数封装为Map集合

下面就等于是一个map集合 put了两次

image-20220223144530745

查询一样

image-20220223144655753

Mbatis模糊查询写法

image-20220223150457600

image-20220223150535723

Mybatis属性优化

别名包用法
其中resultType中的属性com.jt.pojo.User 定义别名.简化其操作.

<select id="findByLike" resultType="com.jt.pojo.User">
    select * from demo_user where name like "%"#{key}"%"
</select>

1。标识注解

image-20220223154305471

2.使用

image-202202231543152273.定义别名包 定义别名包之后,以后的数据只需要写类名即可,使用时会自动的拼接前缀

#3.配置Mybatis
mybatis:
  #定义别名包
  type-aliases-package: com.jt.pojo

sql标签

image-20220223155645384

Mybatis中集合参数用法 array/list

Array类型的参数说明

说明: 一般业务逻辑可能会用到array进行数据的封装. 问题: xml映射文件中如何解析数组
格式如下: Integer[] ids = {1,3,4,5,6};

测试代码:

image-20220223170332236

编辑mapper接口:

image-20220223170349403

编辑mapper映射文件:

image-20220223170212900

Mybatis中集合参数用法Map封装

测试代码
@Test public void findInMap(){ //准备2个集合,测试map集合封装 Integer[] ids1 = {1,3,4,5,6}; Integer[] ids2 = {1,3,4,5,6}; List<User> list = userMapper.findInMap(ids1,ids2); System.out.println(list); }

编辑Mapper接口
List findInMap(@Param(“ids1”) Integer[] ids1,
@Param(“ids2”) Integer[] ids2);

编辑Mapper映射文件

<select id="findInMap" resultType="User">
    select * from demo_user where id in (
        <foreach collection="ids1" item="id" separator=",">
            #{id}
        </foreach>
    )
</select>

例题小结

        <?xml version="1.0" encoding="UTF-8"?>

        <!DOCTYPE mapper SYSTEM "http://mybatis.org/dtd/mybatis-3-mapper.dtd" PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN">

        <!--调用流程:1.编辑Mapper接口 编辑接口方法 2.映射文件与Mapper接口绑定 namespace -->

        -<mapper namespace="com.jt.mapper.UserMapper">

<!--标识使用二级缓存!!!-->


<cache/>

<!--1.id与接口的方法名称绑定 2. 回顾:JDBC->resultSet->遍历结果集->手动封装对象 3. resultType: mybatis自动的将结果集的数据封装为对象如果返回值List集合,则自动封装为List,User充当其中的泛型对象如果返回值User对象.则直接返回User对象 -->


<select resultType="com.jt.pojo.User" id="findAll">select * from demo_user </select>

<!--根据id查询用户数据语法: 动态获取数据 #{属性名称}#号效果: 有预编译的效果 防止Sql注入攻击问题所以以后取值使用#号 -->


<select resultType="com.jt.pojo.User" id="findUserById">select * from demo_user where id= #{id} </select>

<!--规则:1.如果接口方法中,int类型的返回值,则入库之后,mybatis自动回传数据 2.如果接口中传递的是POJO对象.则通过#{属性}取值大小问题:1.windows系统中程序运行不区分大小写.2.Linux系统 严格区分大小写.3.程序猿口头禅: 我在我本机上没问题呀!!!! -->


<insert id="saveUser">insert into demo_user(id,name,age,sex) values (null,#{name},#{age},#{sex}) </insert>

<update id="updateUser">update demo_user set age=#{age}, sex=#{sex}where name=#{name} </update>

<delete id="deleteUser">delete from demo_user where name=#{name} </delete>

<!--知识点1: 通过 #{参数名称/对象中的属性/Map中的key} 知识点2: xml文件中有些字符需要转义 > &gt; < &lt;& &amp; -->


<select resultType="com.jt.pojo.User" id="findUserByAge">select * from demo_user where age>#{minAge} and age < #{maxAge} </select>

<select resultType="com.jt.pojo.User" id="findUserByAge2">select * from demo_user where age>#{minAge} and age < #{maxAge} </select>

<!--Sql标签作用: 抽取公共的部分,可以被其它的Sql引用-->


<sql id="findColumn">select id,name,age,sex from demo_user </sql>


-<select resultType="User" id="findByLike">

    <include refid="findColumn"/>
    where name like "%"#{key}"%"
</select>

<!--需求: Integer[] ids 中的数据一个一个取出来.拼接Sql 知识点: mybatis中如何遍历数组 foreach标签用法:1. collection:需要遍历的集合的类型 1.1 数组类型 关键字:array1.2 list类型 关键字:list1.3 map类型 关键字:Map中的key2. open/close 循环开始和结束标签,一般自己写 3. item 遍历数据的变量名称 4. separator 参数之间的分隔符 -->



-<select resultType="User" id="findInArray">
    select * from demo_user where id in (
    <foreach separator="," item="id" collection="list">#{id} </foreach>
    )
</select>

<!--参数传递是Map集合,所以关键字使用key-ids1 -->



-<select resultType="User" id="findInMap">
    select * from demo_user where id in (
    <foreach separator="," item="id" collection="ids1">#{id} </foreach>
    ,
    <foreach separator="," item="id" collection="ids2">#{id} </foreach>
    )
</select>

</mapper>

测试程序:

package com.jt;

import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest //该注解的作用启动spring容器中,之后动态的获取对象
public class TestMybatis {

@Autowired  //IDEA编译异常 不影响代码的执行
private UserMapper userMapper;

@Test
public void test01(){
    System.out.println(userMapper.getClass());
    List<User> userList = userMapper.findAll();
    System.out.println(userList);
}

/**
 * 业务需求:  根据ID查询数据
 * 参数:  id = 1
 */
@Test
public void test02(){
    int id = 1;
    User user = userMapper.findUserById(id);
    System.out.println(user);
}

/**
 * 实现用户入库操作
 */
@Test
public void saveUser(){
    User user = new User();
    user.setName("元旦快乐").setAge(2022).setSex("女");
    //如果需要返回值  则int接收
    int rows = userMapper.saveUser(user);
    //如果不需要返回值 则void标识
    //userMapper.saveUser(user);
    System.out.println("入库成功:影响:"+rows+"行");
}

/**
 * 3.修改操作  将name="元旦快乐" 改为age=17,sex=男
 */
 @Test
 public void updateUser(){
     User user = new User();
     user.setName("元旦快乐").setAge(17).setSex("男");
     userMapper.updateUser(user);
     System.out.println("修改操作成功!!!");
 }
 //注意事项: 暂时练习时接口方法的参数只写1个. 否则程序必然报错....
 //4.删除操作  将name="元旦快乐"的数据删除
 @Test
 public void deleteUser(){
     String name = "元旦快乐";
     userMapper.deleteUser(name);
     System.out.println("删除成功!!!");
 }

/**
 * 业务: 查询age> 18岁  and  age <100的用户.
 * 知识点:
 *      1.mybatis的参数可以是基本类型或者字符串.
 *      2.如果遇到多个参数,应该使用对象(POJO)进行封装.
 *      3.如果通过pojo封装不方便.则使用功能最为强大的Map进行封装
 *      4.Mybatis的接口方法中只允许传递单值
 */
@Test
public void testFindUserByAge(){
    Map<String,Object> map = new HashMap<>();
    map.put("minAge",18);
    map.put("maxAge",100);
    List<User> userList = userMapper.findUserByAge(map);
    System.out.println(userList);
}

@Test
public void testFindUserByAge2(){
    int minAge = 18;
    int maxAge = 100;
    List<User> userList = userMapper.findUserByAge2(minAge,maxAge);
    System.out.println(userList);
}

/**
 * 需求: 查询name中 包含"君"字的数据
 * Sql:  where name like "%君%"
 */
@Test
public void findByLike(){
    String key = "君";
    List<User> userList = userMapper.findByLike(key);
    System.out.println(userList);
}

/**
 * 业务说明: 集合参数的用法
 * 需求: 查询id=1,3,4,5,6的数据
 * Sql:  where id in (1,3,4,5,6)
 */
@Test
public void findInArray(){
    Integer[] ids1 = {1,3,4,5,6};
    List<Integer> list = Arrays.asList(ids1);
    List<User> userList = userMapper.findInArray(list);
    System.out.println(userList);
}

@Test
public void findInMap(){
    //准备2个集合,测试map集合封装
    Integer[] ids1 = {1,3};
    Integer[] ids2 = {4,5,6};
    List<User> list = userMapper.findInMap(ids1,ids2);
    System.out.println(list);
}

2、Mybatis-动态Sql

if-where标签

编辑测试类

/**
 * 需求: 根据用户不为null的属性充当where条件
 */
@Test
public void testSqlWhere(){
    User user = new User();
    user.setAge(3000).setSex("男");
    List<User> userList = userMapper.findSqlWhere(user);
    System.out.println(userList);
}

编辑UserMapper2接口

image-20220224103222960

编辑UserMapper2映射文件

<!--
    问题说明: 前端数据传递时可能会有null数据.
            如果数据为null则不能充当where条件
    解决方案: 动态Sql实现
    语法:
        <if test="判断条件"> id = #{id}</if>
            true:   则拼接标签内容
            false:  则不拼接标签内容
       <where>标签: 去除where后边多余的and/or
-->
<select id="findSqlWhere" resultType="User">
    select * from demo_user
        <where>
            <if test="id != null"> id = #{id}</if>
            <if test="name !=null">and name = #{name}</if>
            <if test="age !=null"> and age = #{age}</if>
            <if test="sex !=null"> and sex = #{sex}</if>
        </where>
</select>

SET标签

/**
 * 需求: 修改id=1 的数据 name="北极熊",age=4000 sex="男"
 */
@Test
public void testUpdateUser(){
    User user = new User();
    user.setId(1).setAge(5000);
    userMapper.updateUser(user);
    System.out.println("更新成功!!!");
}
<!--根据对象中不为null的属性 当做set条件
    语法: set标签 去除多余1,-->
<update id="updateUser">
    update demo_user
        <set>
            <if test="name !=null">name=#{name},</if>
            <if test="age !=null"> age=#{age},</if>
            <if test="sex !=null"> sex=#{sex},</if>
        </set>
        where id = #{id}
</update>

if-else

测试类

/**
 * 如果name有值,则根据name查询.
 * 如果name没有值,则根据age查询.
 * 如果name/age都没有值,则根据sex查询
 */
@Test
public void testChoose(){
    User user = new User();
    user.setSex("男");
    List<User> userList = userMapper.findChoose(user);
    System.out.println(userList);
}

接口映射文件

<!--
 * 如果name有值,则根据name查询.
 * 如果name没有值,则根据age查询.
 * 如果name/age都没有值,则根据sex查询
   语法类似: if->else-if->else
-->
<select id="findUserByName" resultType="User">
    select name,sex,age,id from demo_user
    <where>
        <choose>
            <when test="name != null"> name = #{name} </when>
                <when test="age != null">age = #{age} </when>
                    <otherwise> sex = #{sex} </otherwise>
        </choose>
    </where>
</select>

ResultMap语法(常用)

解释:

resultType能接收参数是因为POJO对象中的属性与数据库中的字段一样。

如果出现不一样的情况,拿pojo对象接收就会出问题。

这个时候可以用resultMap来自己手动映射,把数据库中的字段跟pojo中对象的属性进行绑定

测试文件

image-20220224142240256

映射文件

<!--
    规则:
        1.如果结果集字段名称与POJO属性的名称不一致
        则mybatis无法自动完成映射.
        2.Mybatis提供了一个属性resultMap(使用最多的).
          支持用户手动映射.
-->
<select id="findAll" resultType="Dog">
    select * from dog
</select>

<!--
    属性说明:  id="唯一标识,不能重复"
              type="映射的POJO对象的类型"
    简化说明:  如果字段名称与属性名称一致则可以省略
              autoMapping="true" 开启自动映射
-->
<resultMap id="dogRM" type="Dog" autoMapping="true">
    <!--1.标识主键-->
    <id column="dog_id" property="dogId"/>
    <!--2.映射结果集-->
    <result column="dog_name" property="dogName"/>
    <!--<result column="age" property="age"/>-->
</resultMap>

3.Mybatis关联查询

常见关联关系

核心: 从一头出发,看向另一头

一对一 : 一个用户/一个ID 老公/老婆 一个员工对应一个部门
一对多: 一个老师对应多个学生, 一个部门对应多个员工
多对一: 多对一本质还是一对一
多对多: 一个老师对应多个学生 一对多
一个学生对应多个老师 一对多 双向一对多

一对一查询

一个员工对应一个部门

image-20220224185240917

image-20220224185216187

<mapper namespace="com.jt.mapper.EmpMapper">

    <!--
    规则:
        1.使用关联查询时,不能出现同名字段,否则映射报错
-->
    <select id="findAll" resultMap="empRM">
        select emp.* , dept.dept_name from emp,dept
        where emp.dept_id = dept.dept_id
    </select>

    <!--
    知识点:
        1.autoMapping="true"
        如果字段名称和属性名称一致,则自动映射
        2.association 一对一对象
        3.javaType    固定搭配 封装对象的类型
        总结:Mybatis可以实现关联查询的数据封装.
            可以为主对象封装数据/同时可以为引用封装数据
-->
<!--  1.先改映射名称  2.在emp中封装dept对象-->
    <resultMap id="empRM" type="Emp" autoMapping="true">
        <id column="emp_id" property="empId"/>
<!--    一对一映射 封装-->
        <association property="dept" javaType="Dept" autoMapping="true">
            <id column="dept_id" property="deptId"/>
        </association>
    </resultMap>

一对多查询

一个部门对应多个员工

image-20220224195737740

image-20220224195748177

image-20220224195804171

Mybatis注解形式

//鸡肋: 1.大公司一般不用,  2.只适用于单表操作.多表操作必须写映射文件
// 注解和映射文件二选一
@Select("select * from dept")
List<Dept> selectAll();
@Insert("insert into dept values (null,#{deptName})")
void saveDept(Dept dept);

image-20220224201617351

4.Mybatis缓存实现

image-20220225094542752Mybatis-一级缓存

说明: 在同一个SqlSession内,实现数据库的共享.
解释: 用户使用同一个SqlSession时,进行多次数据库的查询,由于一级缓存的存在.所以数据库只查询一次.
开关状态: 一级缓存Mybatis默认开启.无需配置.

同一个数据对象

Mybatis-二级缓存

说明: 由同一个SqlSessionFactory(类比:链接池)生产的SqlSession(类比:数据库链接),可以实现数据共享
解释说明: 由同一个SqlSessionFactory生产多个SqlSession(多线程).可以在多线程的条件下,可以实现数据共享.
默认开关: 二级缓存默认条件下是开启的. 但是需要指定哪里使用二级缓存
一个池中多个数据对象共享

image-20220225110848536

@SpringBootTest
public class TestCache {

    @Autowired
    private DeptMapper deptMapper;

    /*
     * 测试:mybatis的一级缓存, SqlSession级别
     * SpringBoot测试说明:
     *   SpringBoot中用户在使用userMapper接口时,用户每调用一次.
     *   SpringBoot就会新创建一个SqlSession.
     * 如何解决多个SqlSession的问题?
     * 解决方案:
     *  利用@Transactional的事务的注解,将多个SqlSession控制为一个.
     */
    @Test
    @Transactional//事务的注解
    public void testCache(){
        List<Dept> all = deptMapper.findAll();
        List<Dept> all1 = deptMapper.findAll();
        List<Dept> all2 = deptMapper.findAll();
        System.out.println(all);
        System.out.println(all1);
        System.out.println(all2);
    }
    /*
     * 测试二级缓存
     * 总结: 多线程条件下共享数据,要求数据必须序列化.
     */

    @Test
    public void testCach2e(){
        //第一次查询数据库获取的list1的集合对象,该对象需要保存到缓存中,为了后续线程使用,该对象必须序列化
        List<Dept> all = deptMapper.findAll();//线程A
        //第二个线程查询数据.有二级缓存的存在.所以从缓存中获取数据.所以直接反序列化该对象获取结果.
        List<Dept> all1 = deptMapper.findAll();//线程B
        //第三个线程查询数据,所以直接反序列化该对象获取结果.
        List<Dept> all2 = deptMapper.findAll();//线程C
    }

}

关于对象序列化问题

说明: 在多线程条件下.数据如果需要共享,必须序列化

image-20220225112915022

关于Mybatis一二级缓存的说明

  1. 默认条件下一二级缓存是开启的. 但是二级缓存需要标记 cache

image-20220225130127697

2.一级缓存在同一个SqlSession中共享数据(单线程)

3.二级缓存在同一个SqlSessionFactory生产的多个SqlSession内共享数据(多线程). 对象必须序列化

4.在真实的生产环境中(集群:多个服务器)使用二级缓存可能存在问题,使用Redis高级缓存服务器代替.

5.Mybatis底层实现原理

class MybatisApplicationTests {
    /*
     * Mysql入门实现步骤:
     *   1.编辑mybatis-config.xml核心配置文件
     *       1.1执行数据源配置
     *   2.编辑POJO实体对象.要求与数据库表中的字段一一对应
     *   3.编辑Mapper接口. 添加接口方法
     *   4.编辑接口的实现类(配置文件方式) 要求namespace id  resultType
     *   5.mybatis加载指定的mapper映射文件
     *   6.创建SqlSessionFactory工厂对象
     *   7.获取SqlSession,开启数据库链接
     *   8.获取接口对象(代理对象)
     *   9.调用接口方法,获取返回值结果
     *   10.关闭sqlSession链接.
     * */
    @Test
    public void testDemo1() throws IOException {
        /*创建SqlSessionFactory 类比:链接池 */
        String resource = "mybatis/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //设计模式1:建造者模式-Builder-.build()
        //设计模式2:工厂模式-Factory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        /*从SqlSessionFactory中获取sqlSession*/
        SqlSession sqlSession = sqlSessionFactory.openSession();
        /*SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SqlSession sqlSession3 = sqlSessionFactory.openSession();*/

        /*获取mapper接口,执行接口方法*/
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        /*Mybatis为接口创建了一个代理对象
            知识点: 框架中通过接口调用方法时,如果没有实现类,则为其创建代理对象
                    代理对象~实现类
         */
        System.out.println(userMapper.getClass());
        List<User> userList = userMapper.findAll();
        System.out.println(userList);

        /*执行之后关闭SqlSession*/
        sqlSession.close();
    }
}

SpringBoot框架介绍

SpringBoot框架介绍
理解: 传统框架在使用时,特别的繁琐 Spring/SpringMVC/Mybatis在使用时需要大量的配置文件. 使用SpringBoot可以简化传统框架的配置文件. 以注解的方式简化开发过程. SpringBoot可以理解为框架的框架(框架的工具API).
优势: “开箱即用” 拿来就用 简化配置的过程.

pom.xml文件说明

/project>
        <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--项目的坐标
    1.标识当前的项目
    2.坐标的位置就是jar包文件的位置
    3.通过坐标可以被其它项目引用
-->
<groupId>com.example</groupId>
<artifactId>springboot_demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_demo1</name>
<description>springboot_demo1</description>

<!--2.指定pom.xml中的配置信息-->
<properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!--指定springboot的版本-->
    <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>

<!--3.当前项目依赖的其它jar包文件  -->
<dependencies>
    <!--3.1 添加依赖信息,其中版本号是默认的无序手写-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!--版本号 <version></version>-->
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

<!--4.依赖的管理器
    历史: 早期项目使用时,需要自己手动的添加依赖jar包文件.可能导致jar包文件不兼容/冲突
         直接导致项目启动出问题. 该问题是开发中的常见诟病.
    SpringBoot优势:
         SpringBoot将市面上常见的jar包都进行了兼容.并且在内部进行了测试.并且
         使用其它第三方框架的时候,只需要简单的配置.可以使用其功能. (开箱即用)
-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.3.7.RELEASE</version>
            <configuration>
                <mainClass>com.jt.SpringbootDemo1Application</mainClass>
            </configuration>
            <executions>
                <execution>
                    <id>repackage</id>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

</project>

关于主启动类说明

启动说明

说明: 主启动类运行,真正起作用的是注解@SpringBootApplication

@SpringBootApplication

public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

主启动类注解说明

@Target(ElementType.TYPE)       //注解对谁有效
@Retention(RetentionPolicy.RUNTIME) //注解的声明周期
@Documented                   //文档支持
@Inherited                //是否可以被继承
@SpringBootConfiguration      //springboot的配置类
@EnableAutoConfiguration      //启动自动化的配置,加载pom.xml文件中的启动项
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),       //包扫描路径,默认条件下是主启动类的包路径. 所以以后写代码在主启动类的同包及子包中编辑.
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

关于YML文件的说明

# 数据结构 key-value

# 语法结构 key:(空格)value

# 注意层级缩进

# 默认字符集: utf-8编码格式 支持中文

server:

​ port: 8080

框架小练习

整合说明

1.SpringBoot 平台
2.Spring框架
3.SpringMVC框架
4.Mybatis框架

框架的搭建

1 导入jar包

pom.xml

    <!--mybatis依赖包-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>

    <!--驱动包-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!--添加lombok的包-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

2 框架层级结构

image-20220228093428797

image-20220228154423412

3 控制层

package com.jt.controller;

import com.jt.pojo.User;
import com.jt.service.UserService;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController //@controller + @ResponseBody
@CrossOrigin    //跨域
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;


//    http://localhost:8080/user/findAll 查询全部用户信息
    @GetMapping ("/findAll")
    public List<User> findAll(){
        return userService.findAll();
    }

//  http://localhost:8080/user/春节/2022/女 实现用户新增 返回新增成功

    @RequestMapping("add/{name}/{age}/{sex}")
    public String add(User user){
        userService.update(user);
        return "新增成功";
    }
//    http://localhost:8080/user/deleteUserById?id=1 删除指定Id的数据 返回删除成功
    @RequestMapping("deleteUserById")
    public String delete(int id){
        userService.delete(id);
        return "删除成功";
    }
//    http://localhost:8080/user/update/元宵节/2022/男/99 将指定ID进行修改操作 返回修改成功
    @RequestMapping("update/{name}/{age}/{sex}/{id}")
    public String update(User user){
        userService.updateFestival(user);
        return "修改成功";
    }
    //http://localhost:8080/user/findUserById?id=xx 查询id=xx的数据 返回User对象
    @GetMapping("findById")
    public User findById(int id){
       User user = userService.findById(id);
       return user;
    }

    //http://localhost:8090/user/findUserBylike?name=王 模糊查询 返回List集合
    @GetMapping("findUserBylike")
    public List<User> findByName(String name){
        List<User> userList = userService.findByName(name);
        return userList;
    }
    //http://localhost:8080/user/findUserByIn?ids=1,3,4,5,6 批量查询 返回List集合

    @GetMapping("findByIds")
    public List<User> findByIds(Integer[] ids){
        List<User> userList = userService.findByIds(ids);
        return userList;
    }
    //http://localhost:8080/user/findUserByAge?minAge=10&maxAge=100 查询数据 返回List集合
    /*
    	多个参数,mapper层加@param,创建成map集合形式
    */
    @GetMapping("findUserByAge")
    public  List<User> findByAge(int minAge,int maxAge){
       List<User> userList =  userService.findByAge(minAge,maxAge);
       return userList;
    }
}

4 service 层 (接口我省略了)

package com.jt.service;

import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    @Transactional
    public void update(User user) {
        userMapper.update(user);
    }

    @Override
    @Transactional
    public void delete(int id) {
        userMapper.delete(id);
    }

    @Override
    @Transactional
    public void updateFestival(User user) {
        userMapper.updateFestival(user);
    }

    @Override
    public User findById(int id) {
        User user = userMapper.findById(id);
        return  user;
    }

    @Override
    public List<User> findByName(String name) {
        List<User> userList = userMapper.findByName(name);
        return userList;
    }

    @Override
    public List<User> findByIds(Integer[] ids) {
       List<User> userList =  userMapper.findByIds(ids);
       return userList;

    }

    @Override
    public List<User> findByAge(int minAge, int maxAge) {
        List<User> userList = userMapper.findByAge(minAge,maxAge);
        return userList;
    }
}

5 mapper层

package com.jt.mapper;

import com.jt.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

@Mapper //将接口交给Spring容器管理 Map<userMapper,JDK代理对象>
//@Repository //将持久层交给Spring容器管理
public interface UserMapper {
    //查询所有的用户信息
    List<User> findAll();

    void update(User user);

    void delete(int id);

    void updateFestival(User user);

    User findById(int id);

    List<User> findByName(String name);

    List<User> findByIds(Integer[] ids);

    //一个map集合 put两次
    List<User> findByAge(@Param("minAge") int minAge,
                         @Param("maxAge") int maxAge);
}

6 映射文件

<?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">
<!--
    调用流程:
         1.编辑Mapper接口 编辑接口方法
         2.映射文件与Mapper接口绑定 namespace
-->
<mapper namespace="com.jt.mapper.UserMapper">
    <!--标识使用二级缓存!!!-->
    <cache/>

    <!--
        1.id与接口的方法名称绑定
        2. 回顾:JDBC->resultSet->遍历结果集->手动封装对象
        3. resultType: mybatis自动的将结果集的数据封装为对象
                       如果返回值List集合,则自动封装为List,User充当其中的泛型对象
                       如果返回值User对象.则直接返回User对象
    -->
    <select id="findAll" resultType="User">
        select * from demo_user
    </select>
    <update id="update" >
        update demo_user set age=#{age},sex=#{sex},name=#{name}
        where id = 1 ;
    </update>
    <delete id="delete">
        delete from demo_user
        where id=#{id}
    </delete>
    <update id="updateFestival">
        update demo_user  set name = #{name} ,age = #{age}, sex = #{sex}
        where id = #{id}
    </update>

  // 
    <select id="findByIds" resultType="User">
        select id,name,age,sex from demo_user where id in(
        <foreach collection="array" item="id" separator=",">
            #{id}
        </foreach>
        )

    </select>

    <select id="findByAge" resultType="User">
        select * from demo_user where
        age &gt; #{minAge} and age &lt; #{maxAge}
    </select>

estival(User user);

User findById(int id);

List<User> findByName(String name);

List<User> findByIds(Integer[] ids);

//一个map集合 put两次
List<User> findByAge(@Param("minAge") int minAge,
                     @Param("maxAge") int maxAge);

}


### 6 映射文件

```java
<?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">
<!--
    调用流程:
         1.编辑Mapper接口 编辑接口方法
         2.映射文件与Mapper接口绑定 namespace
-->
<mapper namespace="com.jt.mapper.UserMapper">
    <!--标识使用二级缓存!!!-->
    <cache/>

    <!--
        1.id与接口的方法名称绑定
        2. 回顾:JDBC->resultSet->遍历结果集->手动封装对象
        3. resultType: mybatis自动的将结果集的数据封装为对象
                       如果返回值List集合,则自动封装为List,User充当其中的泛型对象
                       如果返回值User对象.则直接返回User对象
    -->
    <select id="findAll" resultType="User">
        select * from demo_user
    </select>
    <update id="update" >
        update demo_user set age=#{age},sex=#{sex},name=#{name}
        where id = 1 ;
    </update>
    <delete id="delete">
        delete from demo_user
        where id=#{id}
    </delete>
    <update id="updateFestival">
        update demo_user  set name = #{name} ,age = #{age}, sex = #{sex}
        where id = #{id}
    </update>

  // 
    <select id="findByIds" resultType="User">
        select id,name,age,sex from demo_user where id in(
        <foreach collection="array" item="id" separator=",">
            #{id}
        </foreach>
        )

    </select>

    <select id="findByAge" resultType="User">
        select * from demo_user where
        age &gt; #{minAge} and age &lt; #{maxAge}
    </select>

7.图片上传demo

  • 业务思路:
  • 1.校验图片的类型 jpg|png|gif (正则表达式)
  • 2.校验是否为恶意程序 木马.exe.jpg
  • 3.将图片进行分目录存储 hash方式存储|时间格式存储
  • 4.防止图片重名,使用UUID.

正则表达式

  1. 匹配次数

image-20220307095958877

image-20220307100428807

  1. 匹配固定次

image-20220307100521633

image-20220307100859122

  1. 单个字符

image-20220307100923568

  1. 区间字符

image-20220307102031480

  1. 分组取值

image-20220307102219205

图片demo

package com.jt.service;

import com.jt.vo.ImageVO;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService {

    //定义根目录, Windows采用此 目录  Linux系统需要更换目录
    private String preFilename = "E:/Workspace/JTImage";
    private String preURLPath = "http://image.jt.com";//网络地址前缀

    /*
     * 业务思路:
     *      1.校验图片的类型  jpg|png|gif
     *      2.校验是否为恶意程序 木马.exe.jpg
     *      3.将图片进行分目录存储  hash方式存储|时间格式存储
     *      4.防止图片重名,使用UUID.
     * @param file
     * @return
     */

    @Override
    public ImageVO upload(MultipartFile file) throws IOException {
        //1.读取文件 filename= abc.jpg
        //文件名称大小写问题
        // abc.exe.jpg
        String filename = file.getOriginalFilename().toLowerCase();

        if(!(filename.matches("^.+\\.(jpg||png||gif)$"))){
            return null;//不匹配 不是照片格式 加入失败
        }
        //2.校验是否为恶意程序  abc.exe.jpg  读取图片的长宽
        BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
        int height = bufferedImage.getHeight();
        int width = bufferedImage.getWidth();
        if (height == 0 || width == 0){
            return null;
        }
        //3: 分目录存储 提高检索的效率  按照时间将目录划分 /yyyy/MM/dd/
        //先获取日期路径
        String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
        //"E:/Workspace/JTImage/yyyy/MM/dd/"
        String fileDir = preFilename + datePath;
        //上面就得到了目录所在的文件夹
        File dirFile = new File(fileDir);
        if (!dirFile.exists()){
            dirFile.mkdirs();
        }
        //4.防止文件重名 uuid.jpg
        String uuid = UUID.randomUUID().toString().replace("-", "");
        //得到 .jpg
        String fileType = filename.substring(filename.lastIndexOf("."));
        filename = uuid + fileType;
        //5.实现文件上传
        //"E:/Workspace/JTImage/yyyy/MM/dd/uuid.jpg"
        String filePath = fileDir + filename;
        file.transferTo(new File(filePath));
        //6.封装 imageVo返还数据
        //2022/03/7/uuid.jpg
        String virtualPath = datePath + filename;
        System.out.println(virtualPath);
        //"http://image.jt.com/2022/03/7/uuid.jpg"
        String urlPath =preURLPath + virtualPath;

        return new ImageVO(virtualPath,urlPath,filename);
//
    }

    @Override
    public void deleteImage(ImageVO imageVO) {
        String virtualPath = imageVO.getVirtualPath();
        String path = preFilename + virtualPath ;
        File file = new File(path);
        if (file.exists()) {
            file.delete();
        }
    }

}
/*

        String filename = file.getOriginalFilename().toLowerCase();
            //.+代表名字至少有一个字符
        if (!(filename.matches("^.+\\.(jpg|pbg|gif)$"))){
                return null;
                }
                //2.校验是否为图片
                try {
                BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
                int height = bufferedImage.getHeight();
                int width = bufferedImage.getWidth();
                //不是图片
                if (height == 0 || width == 0){
                return null;
                }
                } catch (IOException e) {
                return null;
                }
                //3: 分目录存储 提高检索的效率  按照时间将目录划分 /yyyy/MM/dd/
                String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
                //E:/Workspace/JTImage/yyyy/MM/dd
                String fileDir = preFilename + datePath;

                File dirFile = new File(fileDir);
                if (!dirFile.exists()){
                dirFile.mkdirs();
                }
                //4.防止文件重名
                String uuid = UUID.randomUUID().toString().replace("-", "");
                int index = filename.lastIndexOf(".");
                //获取 .jpg / png /gif
                String fileType = filename.substring(index);
                //新文件名称
                filename = uuid+fileType;

                //5.实现文件上传
                String filePath = fileDir + filename;
                file.transferTo(new File(filePath));

                //6.封装 ImageVo 返回数据
                //(E:/Workspace/JTImage)/yyyy/MM/dd/uuid.jpg
                String virtualPath = datePath + filename;
                //7.封装网络地址  "http://image.jt.com/yyyy/MM/dd/uuid.jpg"
                String url = preURLPath + virtualPath;
                System.out.println(url);
                return new ImageVO(virtualPath,url,filename);

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值