MyBatis(一)
1.Maven
一种项目管理工具,帮助开发人员进行下载依赖、编译源码、单元测试、项目部署等操作
1.Maven核心概念
-
坐标:
groupId
:公司或组织域名的倒序,有时也会加上项目名称artifactId
:一个项目或者是项目中一个模块的名称version
:版本号
-
POM:
-
含义:Project Object Model项目对象模型
-
思想:POM表示将工程抽象为一个模型,再用程序中的对象来描述这个模型
-
对应的配置文件:POM理念集中体现在Maven工程根目录下的pom.xml配置文件中,所以这个pom.xml配置文件就是Maven的核心配置文件
<!-- 当前工程的坐标 --> <groupId>com.wangshidai.oa</groupId> <artifactId>oa</artifactId> <version>1.0-SNAPSHOT</version> <!-- packaging标签规定当前工程打包的方式 --> <!-- jar:Java工程 --> <!-- war:Web工程 --> <!-- pom:管理其他工程的工程 --> <packaging>jar</packaging> <dependencies> <!-- dependency标签配置具体的一个依赖信息 --> <dependency> <!-- 通过坐标来引用一个想要依赖的jar包 --> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <!-- scope标签配置依赖的范围 --> <!-- 测试过程中使用的jar包以test范围依赖进来 --> <!-- 项目实际运行时真正使用的jar包以test范围依赖进来 --> <!-- 在开发过程中需要用到的“服务器上的jar包”通常以provided范围依赖进来,这个范围内的jar包之所以不参与部署、不放进war包,就是避免和服务器上已有的同类jar包产生冲突 --> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.2.3.RELEASE</version> <scope>compile</scope> </dependency> </dependencies>
-
-
约定目录结构
-
各个目录的作用:
另外还有一个target目录专门存放构建操作输出的结果
-
约定目录结构的意义:Maven为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用
-
3.开发mybatis项目的步骤
![开发mybatis项目的步骤](https://c2.im5i.com/2022/08/16/tZzyj.png)
- 创建maven模块
- pom.xml引入jar包的坐标mysql、mybatis、junit、log4j
- 搭建包结构,com.wangshidai.mapper持久层接口,并创建Account接口
- 复制日志配置文件到resources目录中
- 在resources目录中创建文件夹mapper,专门用于存放持久层的映射xml文件
- 在resources目录中创建mybatis主配置文件sql-config.xml
- 配置数据库数据源
- 配置所有的持久层的映射xml文件
- 写测试类进行测试
MyBatis(二)
1.Mybatis工作原理
![MyBatis工作原理](https://c2.im5i.com/2022/08/16/tZHjG.png)
- 读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。
- 加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml文件可以加载多个映射文件,每个文件对应数据库中的一张表。
- 构造会话工程。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。
- 构建会话对象。由会话工厂创建SqlSession对象,该对象包含了执行SQL语句的所有方法。
- Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态的生成需要执行的SQL语句,同时负责查询缓存的维护。
MappedStatement
对象。在Executor
接口的执行方法中有一个MappedStatement
类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id
、参数等信息。- 输入参数映射。输入参数类型可以是
Map
、List
等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对PreparedStatement
对象设置参数的过程。 - 输出结果映射。输出结果类型可以是
Map
、List
等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。
2.MyBatis对象剖析
JDBC四大核心对象:
对象 | 作用 |
---|---|
DriverManager | 用于注册数据库连接 |
Connection | 与数据库连接连接对象 |
Statement/PreparedStatement | 操作数据库SQL语句的对象 |
ResultSet | 结果集或一张虚拟表 |
MyBatis四大核心对象:
对象 | 作用 |
---|---|
SqlSession | 包含了执行SQL语句的所有方法,类似于JDBC的Connection |
Executor | 根据SqlSession传递的参数动态的生成需要执行的SQL语句,同时负责查询缓存的维护,类似于JDBC的Statement/PreparedStatement |
MappedStatement | 对映射SQL的封装,用于存储要映射的SQL语句的id、参数等信息 |
ResultHandler | 用于对返回的结果进行处理,最终得到自己想要的数据格式或类型,可以自定义返回类型 |
3.SQL语句动态传递参数
#{} | ${} |
---|---|
等同于参数占位符?,即SQL预编译 | 字符串替换,即SQL拼接 |
变量替换后,#{}对应的变量自动加上单引号’’ | 变量替换后,${}对应的变量不会自动加上单引号’’ |
#{}可以防止SQL注入 | ${}不能防止SQL注入 |
在SQL语句中,数据库表的表名或者order by
排序字段不确定,需要外部动态传入,此时不能使用#{}
,因为数据库不允许表名位置使用?
占位符,此时只能使用${}
。其他情况尽量使用#{}
,避免SQL注入
4.各种类型参数输入的解决方案
- 简单类型:只包含一个值的数据类型
- 基本数据类型:
int
、byte
、short
、double
… - 基本数据类型的包装类:
Integer
、Double
、Character
… - 字符串类型:
String
- 基本数据类型:
- 复杂类型:包含多个值的数据类型
- 实体类类型
- 集合类型:
List
、Set
、Map
… - 数组类型:
int[]
、String[]
… - 复合类型
传参时如果有多个参数,需要在每个参数之前加@param
注解,但是不建议这样做,可以将多个参数打包为实体类或HashMap
传入
MyBatis(三)
1.数据库字段和实体类属性对应关系
- 别名:将字段的别名设置成和实体类属性一致
- 使用
resultMap
:- 使用
<resultMap>
标签定义对应关系,再在后面的SQL语句中引用这个对应关系 - 在
<resultMap>
标签中用<id>
标签设置主键,用<result>
标签设置普通字段 - 在
<id>
标签或<result>
标签中,用column
设置指定字段名,用property
指定属性名
- 使用
2.模糊查询
SQL语句中的like '%张%'
在xml配置文件中要写成like concat('%', #{}, '%')
3.批量查询
在配置文件中需要使用<foreach>
循环来获取到一个数组或List
集合
传入数组:
<!-- 参数是数组时,collection的值必须是array -->
<foreach collection="array" item="数组名" open="(" close=")" separator=",">
#{数组名}
</foreach>
传入集合:
<!-- 参数是集合时,collection的值必须是list -->
<foreach collection="list" item="集合名" open="(" close=")" separator=",">
#{集合名}
</foreach>
4.动态查询
在配置文件中需要使用<if>
标签来动态判断是否输入了该条件
<if test="条件">
[and] 查询条件
</if>
如果是单表查询,固定SQL语句中没有WHERE
语句,可以使用<where>
标签
<where>
<if test="条件">
[and] 查询条件
<!-- 当有多个if判断时,where标签会自动删除不需要的条件连接语句and -->
</if>
</where>
在<update>
、<insert>
标签中,同样有<set>
标签起到相似的作用
Servlet
1.桌面程序、C/S、B/S
- 桌面程序:单机运行的程序
- C/S程序:客户端/服务器网络程序,客户端需要安装专门的客户端软件
- B/S程序:浏览器/服务器网络程序,客户端不需要专门的客户端软件,而是使用统一的客户端浏览器进行访问
2.服务器
常见的应用服务器:
- weblogic:实现了JavaEE规范,重量级服务器,又称JavaEE容器
- websphereAS:实现了JavaEE规范,重量级服务器
- JBOSSAS:实现了JavaEE规范,重量级服务器,免费
- Tomcat:实现了JSP/Servlet规范,轻量级服务器,开源免费
3.HTTP协议
Hyper Text Transfer Protocol,超文本传输协议,规范了请求和响应内容的类型和格式
状态码 | 说明 |
---|---|
200 | 运行成功 |
302/307 | 请求重定向(客户端行为,两次请求,地址栏发生改变) |
304 | 请求资源未发生变化,使用缓存 |
404 | 请求资源未找到 |
500 | 服务器错误 |
4.Servlet
Servlet是一种运行于服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面,由它担当客户请求与服务器响应的中间层
Servlet由特殊的技术规范:
- 必须继承某个特定父类
- 必须配置之后才能执行
- 有特定的生命周期
5.Servlet接口的派生类
- Servlet接口、ServletConfig接口
- GenericServlet抽象类:实现了Servlet接口和ServletConfig接口,实现了普通的和http通信协议无关的Servlet接口中的方法
- HttpServlet抽象类:继承了GenericServlet类并提供了和http协议有关的方法
6.get
请求
网页中直接通过地址栏搜索和点击超链接时发送的都是get
请求
7.字符编码
Servlet
获取数据和发送数据前都要先设置字符编码,否则会出现乱码
设置接收数据的字符编码:
request.setCharacterEncoding("utf-8");
设置发送数据的字符编码:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
Web编程(一)
1.排错方法
- **检查前段数据发出去了吗?**看Headers报文
- **检查用户接口(controller控制层)正常收到前端数据了吗?**断点调试,比对前端发送的数据和后端接收的数据是否一致
- **检查业务处理正确吗?**断点调试
- service业务逻辑是否正确
- mapper持久层数据库操作是否正确
- **检查服务器正确响应数据了吗?**检查响应内容和类型是否正确,是否通过
response
返回数据 - 检查前端接收到数据了吗?
- 如果经过以上五步检查还是没有正常运行,那就是前端的js解析响应结果时出问题了
Web编程(二)
1.Servlet
原理
Tomcat服务器启动后,会先加载配置文件web.xml,在该配置文件中必须用
<servlet>
<servlet-name>LoginController</servlet-name>
<servlet-class>com.zhangboyang.controller.LoginController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginController</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
来向外暴露控制层对应的接口地址,但在3.0版本之后就不需要再手动编写接口配置,可以直接在控制层添加注解来声明接口地址
@WebServlet("/login")
public class LoginController extends HttpServlet {
...
}
2.Servlet
生命周期
Servlet
类处理客户端请求和服务器响应,有三个常用方法:
init()
方法只在第一次访问该Servlet
接口时自动调用一次,一般用于数据的初始化- 当服务器收到请求时,在调用
init()
方法后会先调用Servlet
接口中的service()
方法,然后转发给HttpServlet
类中的service()
方法,它会识别请求的方式(get
、post
、put
、delete
),然后再调用相应的接口方法(doGet
、doPost
、doPut
、doDelete
) - 当服务器挂掉或重启时,其管理的所有对象都会被销毁,这时会自动调用
destroy()
方法,一般用于善后工作,比如当服务器挂掉时关闭数据库
3.Servlet
过滤器机制
可以用过继承或实现来创建一个过滤器类
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
//实现过滤机制
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
}
@Override
public void destroy() {
}
}
4.session
容器
在用户登录成功后,可以通过request.getSession()
方法获取到一个HttpSession
类的session
,然后调用session.setAttribute("name", value)
方法保存用户信息,当客户端请求通过过滤器时,如果用户信息已经在session
中保存了,那么就放行,否则就跳转到登录界面
Mybatis(四)
1.“一对一”关联关系
例子:通过编号查询员工信息及他所属的部门信息时,一个员工对应一个部门,员工表和部门表就是“一对一”的关系,此时查询的结果没有对应的实体类来封装
-
利用
HashMap
来接收查询结果-
Mapper
接口中声明抽象方法HashMap queryEmpById(int eid);
-
SQL语句
<select id="queryEmpById" resultType="HashMap"> select e.ename, e.sex, d.deptName from dept d, emp e where d.did = e.did and e.eid = #{eid} </select>
-
-
在员工类中进行一对一配置,用配置过的
Emp
类来接收查询结果**(不推荐使用)**-
在
Emp
类中添加一个部门属性public class Emp{ ... private Dept dept;//员工所属的部门 }
-
Mapper
接口中声明抽象方法Emp queryEmpById(int eid);
-
SQL语句
<resultMap id="empResultMap" type="Emp"> <id column="eid" property="eid"/> <result column="ename" property="ename"/> <result column="sex" property="sex"/> <association property="dept" javaType="Dept"> <id column="did" property="did"/> <result column="deptName" property="deptName"/> </association> </resultMap> <select id="queryEmpById" resultMap="empResultMap"> select e.ename, e.sex, d.deptName from dept d, emp e where d.did = e.did and e.eid = #{eid} </select>
-
2.“一对多”关联关系
例子:查询部门信息及其所有员工信息,一个部门对应多个员工,部门表和员工表就是“一对多”的关系
-
在部门类中进行一对多配置,用配置过的
Dept
类来接收查询结果-
在
Dept
类中配置一对多关系,添加员工属性public class Dept{ ... private List<Emp> empList; }
-
Mapper
接口中声明抽象方法List<Dept> queryDeptsAndEmps();
-
SQL语句
<resultMap id="queryDeptsAndEmpsResultMap" type="Dept"> <id column="did" property="did"/> <result column="deptName" property="deptName"/> <collection property="empList" ofType="Emp"> <id column="eid" property="eid"/> <result column="ename" property="ename"/> <result column="sex" property="sex"/> </collection> </resultMap> <select id="queryDeptsAndEmps" resultMap="queryDeptsAndEmpsResultMap"> select d.did, d.deptName, e.ename, e.sex from dept d left join emp e on d.did = e.did </select>
在查询时,即使不需要主键信息,也要一起查询,否则就没有一对多的效果了
-
-
在部门类中进行一对多配置,然后将一对多查询分成两次一对一查询
-
在
Dept
类中配置一对多关系,添加员工属性public class Dept{ ... private List<Emp> empList; }
-
Mapper
接口中声明抽象方法List<Dept> queryDeptsAndEmps();
-
SQL语句
<select id="queryEmpsByDid" resultType="Emp"> select ename, sex from emp where did = #{did} </select> <resultMap id="queryDeptsAndEmpsResultMap" type="Dept"> <id column="did" property="did"/> <result column="deptName" property="deptName"/> <collection property="empList" ofType="Emp" column="did" select="com.zhangboyang.mapper.EmpMapper.queryEmpsByDid"></collection> </resultMap> <select id="queryDeptsAndEmps" resultMap="queryDeptsAndEmpsResultMap"> select did, deptName from dept </select>
-
3.延迟加载
对于实体类关联的属性到需要使用的时候才查询,也叫懒加载
在Mybatis全局配置文件中配置settings
来开启延迟加载功能
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.Mybatis缓存机制
![缓存机制](https://c2.im5i.com/2022/08/16/tZ8U2.png)
5.一级缓存和二级缓存:
![一级缓存和二级缓存](https://c2.im5i.com/2022/08/16/tZ7em.png)
Mybatis查询顺序是:
- 先查询二级缓存,因为二级缓存中可能有其他程序已经查出来的数据,可以直接拿来使用
- 如果二级缓存没有命中,再查询一级缓存
- 如果一级缓存也没有命中,则查询数据库
SqlSession
关闭前,一级缓存中的数据会写入二级缓存
一级缓存:Mybatis一级缓存只在当前方法中有效,当session
关闭或执行增、删、改操作后,一级缓存会自动清空
二级缓存:可以在namespace
下使用<cache/>
标签开启二级缓存,但二级缓存也只在同一个namespace
下生效,必须保证这个表在整个系统中只有单表操作,而且和这个表有关的全部操作必须在同一个namespace
下。由于以上原因,应该避免使用二级缓存,因为一旦有多个Mapper.xml中都出现了针对这个表的操作,而某个Mapper.xml中做了刷新缓存的操作,那么将会导致查询结果的错误。
Spring入门
1.Spring介绍
- Spring是一个非常活跃的开原框架,它是一个基于IOC和AOP来架构多层JavaEE系统的框架,它的主要目的是简化企业开发
- Spring以一种非侵入式的方式来管理你的代码,Spring提倡“最少侵入”,这意味着你可以适当的时侯安装或卸载Spring
- Spring框架可以降低组件之间的耦合度,实现各层之间的解耦
2.IOC(控制反转)
IOC就是Inversion Of Control,原本一个实例对象是在应用内部创建及维护的,这样各组件各层之间就会相互耦合,而控制反转就是应用本身不再负责依赖对象的创建及维护,把对象的控制权由应用本身转移给了外部容器,这样就实现个各组件各层之间的解耦,这种控制权的转移就是控制反转
//普通创建对象
public class Girl{
private Boy boy = new Boy();
public Void kiss(){
System.out.println(boy.getName());
}
}
3.DI(依赖注入)
DI就是Dependency Injection,依赖注入就是在运行期,由外部容器动态的将依赖对象注入到另一个对象中
public Class Gril{
private Boy boy;
public void kiss(){
System.out.println(boy.getName());
}
}
4.Spring入门
- pom.xml引入Spring的依赖
- 创建Spring核心配置文件
- 创建测试类,项目启动时加载配置文件实例化Spring容器
- 创建实体类
- 在核心配置文件中注册实体对象
- 从Spring容器中获取对象
5.三种实例化Bean
的方式
-
使用构造器实例化
<bean id="boy" class="com.zhangboyang.entity.Boy"/>
-
使用静态工厂方法实例化
public class ObjectFactory{ public Boy createUser(){ return new Boy(); } public static Boy createStaticBoy(){ return new Boy(); } }
<bean id="boy" class="com.zhangboyang.entity.ObjectFactory" factory-method="createStaticBoy"/>
-
使用实例工厂方法实例化
<bean id="objectFactory" class="com.zhangboyang.entity.ObjectFactory"/> <bean id="boy" factory-bean="objectFactory" factory-method="createBoy"/>
6.Bean
的作用域
-
singleton
(默认值),IOC容器中这个bean
只创建一次,每次向外注入的都是同一个对象(单例模式)<bean id="boy" class="com.zhangboyang.entity.Boy" scope="singleton"/>
-
prototype
,每次向外注入都是创建的一个新对象<bean id="boy" class="com.zhangboyang.entity.Boy" scope="prototype"/>
7.属性赋值(依赖注入)
-
通过构造方法注入依赖
<bean id="boy" class="com.zhangboyang.entity.Boy"> <constructor-arg name="name" value="zby"/> </bean>
-
通过
settter
方法注入依赖<!-- 基本数据类型--> <bean id="boy" class="com.zhangboyang.entity.Boy"> <property name="name" value="zby"/> </bean>
<!-- 引用类型,外部bean--> <bean id="gril" class="com.zhangboyang.entity.Gril"/> <bean id="boy" class="com.zhangboyang.entity.Boy"> <property name="gril" ref="gril"/> </bean>
<!-- 引用类型,内部bean--> <bean id="boy" class="com.zhangboyang.entity.Boy"> <property name="gril"> <bean class="com.zhangboyang.entity.Gril"/> </property> </bean>
-
p
标签——命名空间<bean id="gril" class="com.zhangboyang.entity.Gril"/> <bean id="boy" class="com.zhangboyang.entity.Boy" p:gril-ref="gril"/>
-
自动装配
<!-- 根据名称自动装配注册在IOC容器中的对象--> <bean id="boy" class="com.zhangboyang.entity.Boy" autowire="byName"/> <!-- 根据类型自动装配注册在IOC容器中的对象--> <bean id="boy" class="com.zhangboyang.entity.Boy" autowire="byType"/>
-
注解
@Component
:注解标记的普通组件@Controller
:注解标记的控制器组件@Service
:注解标记的服务层组件@Repository
:注解标记的持久化层组件
为了让Spring知道那些地方标记了注解,需要开启扫描目录,将目录中标记如上注解的所有对象注册到IOC容器中自动管理
<context:component-scan base-package="com.zhangboyang"/>
SpringMVC
1.SpringMVC介绍
SpringMVC是基于MVC设计理念的Web框架,它通过一套MVC注解,让POJO称为处理请求的控制器,而无需实现任何接口
SpringMVC天生与Spring框架集成(IOC容器、AOP等),而且支持REST风格的URL请求
特点:
- 轻量级,简单易学
- 高效,基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定优于配置
- 功能强大:REST父类、数据验证、格式化、本地化、主题等
- 简洁灵活
2.SpringMVC框架运行原理
![SpringMVC运行原理](https://c2.im5i.com/2022/08/16/tZYyw.png)
- 前端发起请求到前端控制器(DispatcherServlet)
- 前端控制器请求处理器映射器(HandlerMapping)查找Handler
- 处理器映射器向前端控制器返回Handler,处理器映射器会把请求映射为HandlerExcutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象)
- 前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行Handler
- 处理器适配器将会根据适配的结果去执行Handler
- Handler执行完成会给处理器适配器返回ModelAndView(ModelAndView是SpringMVC框架的一个底层对象,包括Model和View)
- 处理器适配器向前端控制器返回ModelAndView
- 前端控制器请求视图解析器进行视图解析
- 视图解析器向前端控制器返回View
- 前端控制器进行视图渲染
- 前端控制器向用户响应结果
3.REST
REST即Representational State Transfer,(资源)表现层状态转化,是目前最流行的一种互联网软件架构
REST风格的URL将HTTP协议中的四中请求方式GET
、POST
、PUT
、DELETE
分别对应四种基本操作:GET
用来获取资源、POST
用来新建资源、PUT
用来更新资源、DELETE
用来删除资源
SpringBoot(一)
1.SSM架构
SpringMVC + Spring + Mybatis = SSM架构
2.SpringBoot
SpringBoot就是整合了很多优秀的框架,不用我们自己去手动写一堆xml来进行配置的Spring框架子集
优点:
- 快速构建项目
- 对主流的开发框架的无配置集成
- 项目可以独立运行,无需外部依赖
Servlet
容器 - 提供运行时的应用监控
- 极大的提高了开发、部署效率
- 与云计算的天然集成
缺点:
- 集成度较高,使用过程中不太容易了解底层
3.SpringBoot项目创建流程
- 创建SpringBoot项目(模块),自定义名称、包、jdk版本、依赖等
- 配置SpringBoot核心配置文件application.yml,配置端口(
server.port
),配置数据库连接信息(spring.datasource.driver-class-name/.url/.username/.password
),配置MybatisPlus等 - 创建实体类,添加Lombok注解和MybatisPlus注解
- 创建控制层controller及
XxxController
类,添加IOC注册注解和总请求地址注解 - 创建服务层service及
XxxService
接口和对应的XxxServiceImpl
实现类,让接口继承MybatisPlus的IService<Xxx>
,给实现类添加IOC注册注解,再让它继承MybatisPlus的ServiceImpl<XxxMapper, Xxx>
并实现XxxService
接口 - 创建持久层mapper及
XxxMapper
接口,给接口添加IOC注册注解(可以不写,SpringBoot自动扫描持久层对象),让它继承MybatisPlus的BaseMapper<Xxx>
- 在SpringBoot启动类中添加MybatisPlus扫描注解,将包路径改为本项目(模块)的持久层包路径
- 在配置文件夹下创建持久层配置文件夹mapper
MybatisPlus
1.MybatisPlus
MybatisPlus是一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,它封装了crud操作,对于单表的操作甚至可以直接调用API来完成
2.Insert
//插入一条记录
int insert(T entity);
3.Update
//根据whereWrapper条件更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @param(Constants.WRAPPER) Wrapper<T>);
//根据id修改
int updateById(@Param(Constants.ENTITY) T entity);
4.Select
//根据id查询
T selectById(Serializable id);
//根据条件查询一条记录
T selectOne(@param(Constants.WRAPPER) Wrapper<T> queryWrapper);
//根据id批量查询
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
//根据条件批量查询
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
//查询部分字段
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
5.分页
要使用分页插件,需要创建一个配置类开启分页功能
//分页查询
IPage<T> selectPage(Ipage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
//分页查询部分字段
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
6.自动填充
要使用自动填充功能,需要创建一个配置类来配置,然后在需要自动填充的字段上加注解
SpringBoot(二)
1.数据校验
验证客户端输入的数据是否合法
- 客户端校验:JavaScript校验
- 服务端校验:SpringMVC使用validation校验
Spring4.0拥有自己独立的数据校验框架,同时支持JSR303标准的校验框架
Spring在进行数据绑定时,可同时调用校验框架完成数据校验工作
Spring的数据校验需要先给需要校验的属性加相应的注解规定校验规则,然后在数据传入控制层时使用@Valid
注解开启校验,然后还可以给方法加入BindingResult
参数用来对校验结果进行处理
2.全局异常处理
在J2EE项目开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免的会遇到各种可预知或不可预知的异常需要处理,每次都单独处理异常,系统的代码耦合度高,工作量大且不好统一,也很难维护
使用全局异常处理,可以方便的去掉try-catch
这类冗杂难看的代码,有利于代码的整洁和优雅;自定义参数校验时全局异常处理会捕获异常,将该异常统一返回给前端,省略很多if-else
代码;当后端出现异常时,需要返回给前端一个友好的界面的时候就需要全局异常处理
全局异常捕获和处理的方式:
- Spring的AOP(较复杂)
- 注解
@ControllerAdvice
结合@ExceptionHandler
(简单)
3.注解实现全局异常处理
首先需要创建一个全局异常处理类CustomControllerAdvice
,使用@RestControllerAdvice
注解标记该类,然后对各种可能出现的异常写出相应的处理方法,在方法上添加ExceptionHandler(XxxException.class)
注解
这样当代码出现异常时,程序不会按照原代码继续执行,而是会执行全局异常处理类中与出现的异常相匹配的方法
4.业务层异常处理方案
创建一个业务层异常处理类BusinessException
,继承RuntimeException
(或直接继承Exception
),可以定义一些属性来接收异常(比如一般定义一个String message
来存储异常信息),然后在服务层实现类的方法中,可以配合if
判断来抛出一些可能出现的异常
这样当服务层出现异常时,BusinessException
类会自动捕获异常并接收异常信息,然后在全局异常处理类中针对BusinessException
写一个异处理方法,可以通过get()
方法获取异常信息
4.同源策略
不同的域名,不同的端口,不同的协议之间不允许共享资源,保护浏览器安全
5.跨域
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任意不同,都是跨域
解决方案:
- 修改浏览器的设置
- 一般的用户不会设置,用户体验差
- 修改请求的格式:将JSON改为JSONP
- JSONP只支持GET请求
- 只支持跨域HTTP请求
- 需要将前端发送请求和后端接收请求并响应的数据格式都改为JSONP
- CORS
6.CORS
Cross-Origin Resource Sharing,跨域资源共享,是W3C出的一个标准,其思想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。因此,要想实现CROS进行跨域,需要服务器进行一些设置,同时前端也做一些配置和分析
要让后台接口允许被跨域访问,只需要加@CrossOrigin
注解,加在控制层类上则该类中的所有接口都能被跨域访问,加在接口上则只有加了该注解的接口可以被跨域访问
SpringBoot(三)
1.开发规范常用对象
- VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来
- DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里泛指用于展示层与服务层之间的数据传输对象
- POJO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么数据表中的每个字段(或若干个)就对应POJO的一个(或若干个)属性
2.文件上传
利用Apache fileupload组件实现,在SpringMVC中使用封装了的MultipartFile接口实现文件上传
SpringBoot(四)
1.Swagger
Swagger是一个规范且完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,目标是对REST API定义一个标准且和语言无关的接口
- 支持API自动生成同步的在线文档:使用Swagger后可以直接通过代码生成文档,不再需要自己手动编写接口文档了,对程序员来说非常方便,可以节约写文档的时间去学习新技术
- 提供Web页面在线测试API:光有文档还不够,Swagger生成的文档还支持在线测试,参数和格式都定好了,直接在页面上输入参数对应的值即可在线测试接口
2.Swagger注解
1.@Api//用在类上,说明该类的作用
2.@ApiOperation//注解来给API增加方法说明
3.@ApiImplicitParams//用在方法上包含一组参数说明
4.@ApiImplicitParam//用来注解给方法入参增加说明
5.@ApiResponses//用来表示一组响应
6.@ApiResponse//用在@ApiResponses中,一般用于表达一个错误的响应信息
3.Swagger使用配置
要使用Swagger,必须先导入pom依赖,然后创建一个SwaggerConfig
配置类
4.easyExcel
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel
使用easyExcel需要先导入pom依赖,然后根据官方文档开发所需要的上传或下载(Excel文件)接口
SpringBoot(五)
1.AOP
Aspect-Oriented Programming,面向切面编程,是一种通过动态代理实现程序功能扩展和统一维护的技术
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的复用率,同时提高了开发效率
AOP就是要关注三件事:
- 在哪里切入,比如权限校验等非业务操作在哪些业务代码中执行
- 在什么时候切入,是业务代码执行前还是执行后
- 切入后做什么,比如做权限校验或者日志记录等
![AOP](https://c2.im5i.com/2022/08/16/tZG1j.png)
2.代理模式
代理(proxy)设计模式提供了目标对象另外的访问方式,即通过代理对象访问目标对象,这样做的好处就是可以在实现目标对象的基础上扩展额外的功能操作
![代理模式](https://c2.im5i.com/2022/08/16/tZopJ.png)
3.静态代理
定义接口或是父类,被代理对象与代理对象一起实现相同的接口或者继承相同的父类
- 优点:可以做到在不修改目标对象的功能的前提下,对目标对象功能扩展
- 缺点:
- 因为代理对象需要与目标对象实现一样的接口,所有可能需要创建很多的代理类
- 一旦接口增加方法,目标对象与代理对象都要维护
4.动态代理
- JDK代理
- 代理对象不需要实现接口,目标对象一定要实现接口
- 代理对象的生成利用JDK API完成,动态的在内存中构建代理对象,需要指定创建代理对象或目标对象实现的接口的类型
- Cglib代理(子类代理):在内存中构建一个子类对象从而实现对目标对象功能的扩展
- Spring的核心包重已经包括了Cglib功能,直接引入spring-core.jar即可
- 引入功能包后就可以在内存中动态构建子类
- 代理的类不能为
final
,否则报错 - 目标对象的方法如果为
final
或static
,那么就不会被拦截,即不会执行目标对象额外的业务方法
5.Spring代理对象机制
Spring在运行期创建代理有两种代理方式:
- 若目标对象实现了若干接口,Spring就会使用JDK动态代理
- 若目标没有实现任何接口,Spring就会使用Cglib库生成目标对象的子类
6.AOP要点
- AOP:面向切面编程,让关注点代码与业务代码分离
- 关注点:重复代码就是关注点
- 切面(
Aspect
):关注点形成的类就叫做切面(类),面向切面编程就是将很多重复代码抽取出来,再在运行的时候动态植入到业务方法上 - 切点(
Pointcut
):执行目标对象方法,动态植入切面代码。可以通过切入点表达式,指定拦截哪些类的哪些方法,给指定的类在运行的时候植入切面类代码。切点分为execution
方式和annotation
方式 - 处理(
Advice
):切面必须要完成的各个具体工作 - 连接点(
Joint point
):切入关注点在程序代码中的具体位置,核心业务方法
7.AOP常用注解
1.@Aspect:标记这是一个切面类
2.@Component:将该类交给Spring管理
3.@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)"):指定切点
4.@Before("pointCut_()"):前置通知: 目标方法之前执行
5.@After("pointCut_()"):后置通知:目标方法之后执行(始终执行)
6.@AfterReturning("pointCut_()"):返回后通知,执行方法结束前执行(异常不执行)
7.@AfterThrowing("pointCut_()"):出现异常时候执行
8.@Around("pointCut_()"):环绕目标方法执行
8.SpringBoot事务
在Spring中,事务有两种实现方式,分别是编程式事务管理和声明式事务管理
- 编程式事务管理:使用
TransactionTemplate
或者直接使用底层的PlatformTransactionManager
。对于编程式事务管理,Spring推荐使用TransactionTemplate
- 声明式事务管理:建立在AOP之上的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完毕目标方法之后根据执行情况提交或者回滚事务。声明式事务管理不需要入侵代码,通过
@Transactional
就可以进行事务操作,更快捷简单