servlet:
1.第一次发送请求会生成servlet实例
2.当服务器关闭时候,servlet实例会进行销毁
3.servlet是单例多线程的,如果多个请求访问servlet,那么每个请求都会实例化一个request和response,但是servlet是单个的。
服务器端的编程基础
服务交互
1.B/S browser server 和 C/S client server
客户端采用的必须是标准浏览器,服务器端采用的是标准的服务器,客户端和服务器之间采用的是标准的HTTP协议进行通讯
2.B/S的优点
(1)编程简单,不需要编写协议及通讯模块
(2)不需要用户手动下载安装,并且后期版本升级不需要用户手动更新
3.Tomcat
(1.tomcat对应版本6789
(2.解压之后,启动tomcatXXX/bin/startup.bat server startup in XXXseconds
(3.localhost:8080 127.0.0.1:8080
ps:tomcatXXX/bin/shutdown.bat
手动启动tomcat
Servlet是制定用于扩展web服务器的组件规范。servlet是一种规范。
扩展web服务器?早期web服务器只能看静态界面,不能处理动态文件,所以要进行扩展
如何扩展?
组件+容器
组件:符合规范的实现特定功能的软件程序(java类)
容器:符合规范,为组件提供运行环境的,并且管理组件的生命周期的软件模块。
如何定义servlet组件?
步骤一:定义java类继承httpServlet
步骤二:重写service方法
步骤三:配置servlet组件(在web.xml文件中配置)
如何在服务器中获取请求参数?
http://localhost:8080/servlet01/hello?uname=zs
参数只有一个值
req.getParameter(参数名);
参数有多个值用
http://localhost:8080/servlet01/hello?uname=zs
7.servlet中如何获取中文参数
GET请求:
需要查看tomcat的版本
tomcat6:在server.xml文件中添加URIEncoding="utf-8"
tomcat8:容器已经处理好,可以直接获取到中文
POST请求:
req.setCharacterEncoding("utf-8");
8.服务器如何输出中文?
res.setContentType("text/html;charset=utf-8");
作用1.设置服务器返回的文件类型时html类型
作用2.通知浏览器html的编码格式是utf-8
9.
(1)根据localhost连上本机,根据端口8080 连上tomcat服务器
(2)根据servlet01 去tomcat/webapps目录下查找同名文件夹
(3)如果找到,则容器根据/test跟该文件夹下的web.xml进行匹配,匹配url-pattern
(4)如果匹配上,则根据对应servlet-name值去servlet中找到servlet-class
(5)容器根据路径找到组件的字节码文件,利用类的反射创建Servlet组件的实例对象,然后调用service方法。
10Servlet运行原理
a.浏览器根据ip:port与服务器建立连接
b.浏览器通讯模块将数据按照http协议打包
c.发送请求
d.服务器通讯模块按照http协议拆包,并自动放入到request对象中
e.服务器根据请求地址查找servlet组件,实例化该组件对象
f.调用组件的service方法
g.服务器通讯模块从response中,取出数据,并按照http协议打包
h.服务器给出响应
i.浏览器通讯模块根据http协议拆包生成新的页面
================================================================
HTTP协议
是一种应用层协议,定义浏览器和web服务器之间通讯的过程以及数据包的格式。
通讯过程:step1:浏览器与服务器建立连接
step2:浏览器打请求包,根据http协议进行打包,发送请求
step3:服务器打包(响应包) 返回响应
step4:服务器会关闭链接
特点:一次请求一次响应,响应结束请求关闭
优点:提高资源利用率
数据包格式:
请求包
part1;请求行
a.请求类型(get post)
b.请求资源路径
c.协议类型及版本号http/1.1
part2:若干消息头
由浏览器根据w3c规范生成一些有特定含义的键值对
part3:实体内容
get请求,空
post请求数据在实体内容中,参数名:值
响应包
part1;响应行
a.协议类型及版本号http/1.1
b.响应状态码
200-正确
400
500-程序内部代码错误
404-找不到地址
405-servlet中service方法定义出错 无service方法
302
part2:若干消息头
由服务器根据w3c规范生成一些有特定含义的键值对
其中content-type在服务器中可以设置
part3:实体内容
第三方抓包工具fiddler
GET和POST请求
哪些是get请求?
--直接在地址栏输入地址
--点击a链接
--img的src
--form表单的默认提交方式
哪些是post请求?
--form表单
区别?
get方式不安全
get请求携带参数个数和大小有限制。
post参数个数和大小没有限制
若参数较多,或者包含敏感信息,建议用post,其他情况用get
create table admin(id int primary key auto_increment,username varchar(100
),pwd varchar(100), realname varchar(100));
step1:定义一个add页面
step2:定义AddServlet组件
--获取表单数据
--使用jdbc连接数据库,并将数据入库
--提示添加成功
长连接和短连接的区别:
1.什么叫重定向
浏览器向服务器发送请求,服务器返回一个302状态码和一个地址,告诉服务器要重新发送请求,浏览器接收到响应后,立刻向改地址发送location请求
如何重定向?
resp.sendRedirect(新地址);
重定向的注意点:
1.重定向之前不能调用pw.close()或者pw.flush()方法
2.在重定向之前会清空响应中的缓存数据
重定向的特点
1.重定向之后地址栏地址发生改变
2.重定向的地址是任意的
3.重定向不共享request和response对象
Dao(Data Access Object)
封装了数据的访问逻辑,调用者不需要知道内部封装的细节,当封装细节发生改变时候,不影响调用者。便于后期维护,提高代码利用率。
如何定义一个dao
a.创建实体类
实体类中私有的属性 类型要与表中一一对应
b.定义dao接口
在接口中定义抽象方法,不要涉及具体的技术实现
c.定义接口的实现类
使用具体技术重写抽象方法
工厂设计模式
设计模式是为了解决同一类相同问题而提出的方案
工厂设计模式:返回一个符合接口要求的对象。调用者不需要知道创建对象的细节,而且当创建细节改变时,不影响调用者。
容器是如何处理请求资源路径?
localhost:8080/servlet01/list 这个是url
ps:请求资源路径uri:从端口号后面开始 如/servlet01/list
1)在请求发起之后,到达容器时候,容器先根据应用名去webapps下找同名文件夹
2)如果找到,则容器根据/list与该文件夹下的web.xml进行匹配url-pattern;如果此时能够匹配,则根据servletname找servletclass调用方法执行请求;如果不能匹配,则将该请求当成静态资源文件处理,根据请求地址找同名文件,如果能够找到则显示页面,如果找不到报404
3)如果找不到文件夹,则报404
url的匹配规则
a.完全匹配 写法:/开头 比如/list、/add
b.通配符匹配 写法:/开头但是可以跟通配符 *
c.后缀匹配 写法:不能以/开头 可以指定后缀单词 一般*.do 或者*.action
Servlet相关类和接口
1)Servlet接口
init(ServletConfig config)
destroy()
service(ServletRequest,ServletResponse)
2)GenericServlet抽象类实现了Servlet接口的init和destroy()
3)HttpServlet抽象类继承了GenericServlet抽象类
Servlet生命周期
容器创建servlet对象,分配资源,调用方法,并销毁实例的过程。
整个过程分为四个阶段
阶段1.容器创建servlet实例 发送请求的时候去创建servlet,懒加载。
默认情况下:当请求到达容器,容器根据web.xml找到需要实例化的组件
会先检查当前内存中是否包含该组件对象,如果不包含,才会创建servlet对象
否则返回上一次的servlet对象
非默认情况:可以通过load-on-startup进行修改创建servlet对象的时机。设置的值为<0的整数,数值越小优先级越高
阶段2.初始化 给当前实例分配资源(就是调用init方法)
容器在实例化组件之后,会立即初始化,如果要重写init方法,建议重写带参数的init方法
阶段3.调用方法(默认调用的service)
doGet和doPost一个只能使用Get方法一个只能处理Post方法
默认调用service方法,容器根据请求方式去调用doGet()或者doPost()方法,若这两个都没有则调用service。
阶段4.销毁阶段 容器根据自身算法将一定时间(正常情况在半小时)内不在使用的servlet实例进行销毁
容器在销毁之前会执行destroy()方法,destroy的目的是在销毁servlet之前通过代码手动将相关联的内容进行销毁
5.JSP java server page servlet
sun公司定义的一种用于在服务器端动态生成页面的技术规范
目的:替换servlet中大量的输出页面逻辑代码,如替换printWriter.print();
如何写一个jsp
1)写一个XXX.jsp文件
2)编写html相关内容(html+css+js)
3)编写java代码
在JSP中写java代码
<% java代码块 %>
<%= java表达式%>
转发:一个web组件将未完成的事情交给另一个web组件去继续完成。通常情况下是servlet将数据交给jsp去展示
如何进行转发?
step1:将数据绑定到request对象上 request.setAttribute(String 绑定名,Object 绑定值);
step2:获取转发器 request.getRequestDispatcher(String 转发地址);
step3:通过转发器进行转发 requestDispatcher.forward(request,response);
转发的注意点
1)转发之前不能调用printWriter.close()或者printWriter.flush();
2)转发和重定向之前会清空response中的缓存数据
转发特点:
1)转发只能在同一个项目中,不能跨项目;
2)转发之后,浏览器地址栏地址不会改变
3)转发之间的组件可以共享request和response对象。
转发和重定向的区别
1.转发共享request和response,因为只发送了一次请求,而重定向不共享,因为发送了2次
2.转发是发生在服务器内部的,不能转发到服务器之外或者项目之外,而重定向可以
3.转发的地址是不变的,而重定向地址改变了。
------------------------------20190917
转发和重定向的相同点:都会清空response中的内容
servlet获取参数时候 req.getParameter("input的name值");
从结果集中取值,resultSet.getInt("表中的字段名字")
对象中取值obj.get属性名();
状态管理:
就是将浏览器和服务器多次交互过程中,所涉及的数据保存下来。
状态就是数据
管理就是保存
Cookie机制:数据保存在浏览器端
Session机制:数据保存在服务器端
Cookie概念
浏览器向服务器发送请求,服务器创建Cookie对象,以set-cookie消息头的方式发送给浏览器。浏览器将cookie数据保存起来,当下一次再次访问服务器,会将cookie以消息头的形式发送给服务器,从而达到状态管理的目的。
Cookie对象的创建
Cookie cookie = new Cookie(String name,String value);
Cookie的保存时间 默认浏览器将cookie保存在内存中,可以通过设置修改Cookie的保存时间
cookie.setMaxAge(int seconds) seconds<0 保存在浏览内存中 只要浏览器不关闭,cookie就存在
seconds>0 以文件的形式保存在磁盘上
seconds=0 立即删除
cookie的替换
//删除login这个cookie状态
//创建同名cookie内容""
//将新cookie保存时间设置为0
//用新cookie替换旧的cookie
cookie的访问路径:必须是其添加路径的同级或者子级
cookie局限性
1.cookie可以被用户禁止
2.cookie里面不能存对象,只能保存字符串。
3.cookie只能保存少量数据(个数和大小都有限制)
4.cookie不安全
Session机制:浏览器向服务器发送请求,服务器创建一个session对象,然后该对象有一个唯一标识叫sessionID,服务器将sessionID通过cookie形式发送给客户端,浏览器将其保存在内存中,当浏览器再次发送请求时,会将sessionID以cookie消息头的形式发送给服务器。服务器根据sessionID找到上一次的session对象,从而达到状态管理的目的。
Session对象不用创建,会自己创建。
----------------------------------------------------20190918
服务器如何获取session
req.getSession(boolean flag);
flag:true 浏览器向服务器发请求,服务器根据请求包查找是否sessionID,如果没有,则自动创建session,并生成sessionID,如果有sessionID,服务器会根据sessionID会查找session,如果找到则使用旧的session,如果没有找到则创建session
:false 浏览器向服务器发送请求,若服务器找不到sessionID或者根据sessionID找不到session则返回null,若有,则返回旧的session
req.getSession()等同于req.getSession(true)(推荐)
a.获取sessionID
b.绑定数据
session.setAttribute(String name,Object obj);
c.获取数据
session.getAttribute(String name);
如果name不存在,则返回null;
修改session的保存时间 默认是30min
1.修改容器的session保存时间在tomcat/conf/web.xml
<session-config>
<session-timeout>超时时间(分钟)</session-timeout>
</session-config>
2.修改项目的web.xml
<session-config>
<session-timeout>超时时间(分钟)</session-timeout>
</session-config>
3.通过编程的方式修改超时的时间。
httpSession.setMaxInactiveInterval(int seconds);
session的删除
session.invalidate();
浏览器记录的是sessionID,而sessionID是依赖于cookie机制返回的。若用户禁止了cookie,那么session就失效了。
解决方案:url重写
当用户禁止cookie后,想继续使用session,则使用url重写。
使用场景
1)a链接的href中 <a href="<%=response.encodeUrl("count") %>">访问次数</a>
2)form表单action
3)重定向response.sendRedirect(response.encodeRedirectUrl("请求地址"));
相对路径和绝对路径
相对路径不以/开头的路径就是相对路径
绝对路径就是以/开头
转发:以"/"开头 是应用名之后
链接/form表单action/重定向 "/" 从应用名开始写(包含应用名)
ps:在企业开发中,绝对路径居多
4.过滤器
过滤器是servlet规范中一种特殊的类,可以对servlet请求进行拦截并处理
如何写过滤器
1.写一个java类,实现filter接口
2.重写filter中的方法
3.在web.xml中配置我们的过滤器,并且必须配置在servlet之前,配置在servlet之后就不能拦截了。
------------------------------------------------------20190919
过滤器
可以配置多个过滤器,过滤器的执行顺序是和filtermapping配置顺序是一致的‘
过滤器的优点:
1.可操作性型强,增加或者删除功能比较方便,不影响之前的代码
2.可以将多个组件相同的业务逻辑写入过滤器中,方便后期维护
监听器
servlet中一个特殊的类,用来监听容器中产生的事件,并进行处理。
监听的事件包括分为两类
type1:与生命周期相关的事件,比如容器创建或者销毁了request/session/ServletContext对象
type2:绑定事件,调用了request/session/ServletContext对象的setAttribute()和removeAttribute()方法
如何写监听器
step1:写一个java类,实现特定接口
step2:重写方法
step3:写配置文件
ps:配置文件的书写顺序
全局初始化变量-监听器-过滤器-servlet
ServletContext 上下文对象,容器内每一个应用创建的一个唯一对象,一个应用只有一个servletcontext对象,该对象一直存在,除非容器关闭或者应用删除
servletContext的获取方式:
1)GenericServlet:getServletContext()
2)HttpSession:getServletContext()
3)ServletConfig:getServletContext()\
ServletContext的相关方法
a.绑定数据 servletContext.setAttribute(String name,Object object)
servletContext.getAttribute(String name)
servletContext.removeAttri(String name)
b.获取全局参数
servletContext.getInitParameter(String name);
c.根据逻辑路径获取物理路径
servletContext.getRealPath(String 逻辑路径url)
ps生命周期
request:一次请求一次响应
session:一次会话期间,浏览器从打开到关闭
servletContext
启动容器就会生成servletContext
servlet线程安全问题
servlet对象在内存中只有一份,若多个浏览器发送相同请求
服务器会启动多个线程访问同一个servlet对象,若在service方法中修改同一个变量的值。可能产生线程安全问题。
JSP组成部分
-ahtml css js
-b java代码块
-c java表达式
-d jsp声明
执行步骤:
1.将jsp文件转换成java文件
html css js -> out.write输出
<%=%> -> out.print输出
<%%> -> service方法照搬
2.容器负责实例化,初始化,就绪,销毁
指令
<%@指令名 属性名=属性值%>
page指令 import导包
language:语言 默认是java
contentType:内容类型及编码格式
session属性:true/false 默认是true 是否可以使用session对象
errorpage:用来指定错误页面
isErrorpage true/false 用来表示当前页面是错误处理页面
taglib prefix="" uri=""
jsp中九大隐含对象
out
request
response
session
application
exception --当前页面必须是错误处理界面
page :jsp
pageContext:页面上下文
config:配置文件对象
注释 <!-- 注释内容 --> 注释的代码会运行 不显示
<%-- 注释内容 --%> 注释的代码不会运行也不会显示
jsp标签:将页面中的java代码转换成类似于html标签的形式 可以优化jsp页面,方便后期维护
jstl标签 java standard taglib
----------------------------------------------------------20190920
jstl标签+el表达式
el表达式:是一种计算规则,可以用来输出属性的值,也可以设置属性的值。
el表达式的语法:${绑定名} 绑定名是从4大作用域去获取的 pageContext/request/session/application
request.setAttribute("user","dekeshi");
${user} ->打印绑定名为user的对象的uname属性
1)找到绑定名为user的对象
2)调用u.getUname();
绑定名的查找顺序 容器依次从四大作用域中最小的作用域开始查找
el表达式
-1访问bean属性
语法:${user.name}
容器根据绑定名user 依次从pageContext,request,session,application四个对象中查找,若找到,则调用该对象的getName()方法,若全都找不到,返回""
可以通过设置指定查找范围pageScope,requestScope,sessionScope,applicationScope
${user["name"]}和${user.name} 功能一模一样
-2.获取请求参数
语法:${param.name}
-3.常规运算
算术运算
逻辑运算
关系运算
empty运算:以下四种情况结果为true
a.绑定名写错
b.绑定的值是""
c.绑定的值是null
d.绑定的值是集合且集合内容为空
jstl标签
步骤一:引入jar包
步骤二: 在jsp页面上通过taglib指令引入标签库
1.page
pageContext
config
2.jstl标签+el表达式
page context session application 四个作用域 作用方位从小到大
el表达式
是sun公司制定的计算规则,可以用来输出属性的值,也可以设置属性的值
el表达式语法
$(绑定名)
如:${user.uname} ->打印绑定名为user的对象的uname属性值
执行原理
1)找到绑定名为user的对象 u
2)调用u.getUname()
绑定名的查找顺序: 容器依次从四大作用域进行查找
(pageContext,request,session,application)
-1.访问bean属性
语法:${user.name}
容器根据绑定名为user 依次从pageContext,request,session,application
四个对象中查找,若找到,则调用该对象的getName()方法.若全都找不到,
返回""字符串
可以通过设置 指定查找范围pageScope,requestScope,sessionScope,
applicationScope
语法:${user["name"]} 结果与${user.name}相同
-2.获取请求参数
语法:${param.name}
-3.常规运算
算术运算:+ - * /
逻辑运算:&& || !
关系运算:> < ==
empty运算:以下四种情况结果为true 其他都为false
a.绑定名写错
b.绑定的值是""
c.绑定的值是Null
d.绑定的值是集合 集合内容为空(集合中没有元素)
2.2 jstl标签
step1:引入jar包
step2:在jsp页面通过taglib指令引入标签库
step3:在jsp页面中使用标签库中的标签
* 判断标签
<c:if test="" var="" scope="">标签体</c:if>
test:true/false
如果返回的是true 则执行标签体 若是false 则不执行
var:指定一个绑定名 绑定值就是test的结果
scope:指定绑定范围 方位指四大作用域的范围
* 分支标签
<c:choose>
<c:when test=""></c:when>
<c:when test=""></c:when>
<c:when test=""></c:when>
...
<c:otherwise></c:otherwise>
</c:choose>
PS:至少放一个when 至多放一个otherwise
* 循环标签
遍历对象是集合
<c:forEach items="" var="" varStatus=""></c:forEach>
items:指定需要遍历的集合
var:指定一个绑定名 绑定值是每次遍历的元素
varStatus:封装了一个对象,该对象中有很多属性,其中的两个属性
分别是
index:当前遍历的下标
count:当前遍历的次数
遍历的对象是数值
<c:forEach begin="" end="" var="">
分页逻辑:
1)求总页数
表中总记录 totalnum
每页显示记录数 pageSize
pages = totalnum%pageSize==0?totalnum/pageSize:totalnum/pageSize+1;
totalnum = select count(*) from admin;//可省略
findAll()->返回List集合->集合的size()就是总记录数
建议:在AdminDAO 添加 getTotalpage()-获取总页数
2)在list.jsp页面 得到pages
遍历pages 生成真实页码
3)点击上一页 下一页
在AdminDAO中新增 findByPage()
select * from admin limit ?,3;
? = (page-1)*pageSize
PS:建议把AdminDAOImpl复制一份备用
list.jsp 复制一份备用
-------------------------------------------------------------2019.09.23
ajax(异步交互技术)
ajax是可以改善用户体验的技术。实质上是利用浏览器的ajax对象(XMLHttpRequest)向服务器发送异步请求(ajax对象在发送请求的同时,用户可以进行其他操作),当服务器返回数据时,浏览器可以根据服务器返回的数据局部更新页面
特点:异步请求,局部刷新
2.如何获取ajax对象
3.通过ajax对象发送请求
get:
步骤一:初始化
xhr.open(请求类型,请求地址,是否异步)
步骤二:注册监听
xhr.onreadystatechange = f1;
步骤三:发送请求
xhr.send();
post:
步骤一:初始化
xhr.open(请求类型,请求地址,是否异步);
xhr.setRequestHeader("content-type:application/x-www-form-urlencoded");
步骤二:注册监听
xhr.onreadystatechange = f1;
步骤三:发送请求
xhr.send();如果有参数,参数跟在send中
4.ajax相关属性
1)onreadystatechange:给ajax对象绑定事件处理函数
2)readyState:ajax对象与服务器的通讯状态
0 1 2 3 4:服务器响应状态结束
3)服务器返回的内容
4)responseText:服务器返回的文本内容
5)服务器返回的状态码(200 404 405 )
5.JSON(JavaScript object notation)
是一种数据交换标准,定义了浏览器和服务器之间的数据交换格式
比如将java对象转成浏览器识别的js对象
json语法:
1)json语法表示单个js对象{"name":"张三","age":15} json对象
a.属性名加""
b.属性值若是字符串类型 需要加"",其他可以不加
ps undefined string boolean null number object
2)json语法表示js数组对象[{},{},{},{}]
如何把java对象转换成json格式字符串
java单个对象
JSONObject.fromObject(java单个对象).toString();
java多个对象
JSONArray.fromObject(java对象).toString();
json字符串转js对象
spring中支持ajax,spring会自动将对象转换成json字符串
6.jquery对ajax的支持
$.ajax(对象);
对象={url:请求地址,
type:请求方式,
data:请求参数,//如果参数是多个可以直接跟对象
dataType://预期服务器返回的数据类型 json text html xml js...
success:function(data){},//服务器成功返回响应后执行的函数,其中的data代表服务器返回的数据
error:function(xhr,txt){}//服务器响应失败执行的函数
xhr:ajax对象
txt:状态描述信息
}
insert into sale values(null,'lian',90);
insert into sale values(null,'wawa',100);
insert into sale values(null,'围',105);
insert into sale values(null,'鞋',111);
insert into sale values(null,'围裙',157);
---------------------------------------------20190924
1.spring框架
半成品,封装了通用的处理逻辑,敏捷开发
spring的定义:轻量级的开源框架 简化企业级开发,提倡最少的侵入
优点:IOC AOP,基于这些特性可以降低组件之间的耦合度,便于后期维护。
2.spring容器
spring容器是一个核心的组件,类型beanfactory或者applicationContext
推荐使用applicationContext,提供了更丰富的企业级方法
ApplicationContext实现类
1)ClassPathXmlApplicationContext:可以根据类的路径进行查找(推荐)
2)FileSystemXmlApplicationContext:根据文件路径查找
3.通过spring容器管理bean组件
1)写bean组件对应的对象
2)在配置文件中管理bean组件
4.spring容器的作用
a.spring容器负责创建及销毁bean组件(类似于DaoFactory)
b.spring可以采取不同的模式创建bean
c.spring提供了IOC机制
d.spring提供了AOP机制
5.spring中的IOC控制反转
控制:负责对象之间的关系指定,对象的创建,初始化,销毁等逻辑
控制反转:将控制逻辑交给容器,这样当后期对象之间的关系发生改变,只需要修改配置即可,降低组件之间的耦合度,提高代码复用性,便于后期维护
DI(Dependency injection)依赖注入
6.spring配置详解
bean元素:
使该元素的创建方式交给spring容器,bean用来描述容器需要管理的对象
id属性:唯一标识 不可重复
name属性 :给bean属性命名,可以重复
class属性:被管理对象的完整类名
scope属性:singleton 默认spring容器创建的bean是单例的
prototype 非单例
request:web环境下生命周期跟request一致
session:web环境下对象的生命周期跟session一致
生命周期相关属性
init-method:spring容器在对象创建之后立刻调用
destroy-method:spring容器在对象销毁之前立刻调用 只有在单例模式下才会触发destroy
容器创建对象的时机:
单例:默认容器启动时候创建bean对象 但是可以通过lazy-init="true",延迟到调用getbean的时候再创建
原型(多例):默认getbean时候创建
容器创建对象的方式
1.默认调用无参构造器
2.静态工厂 - 目的就是为了创建的时候添加参数<bean id="userDaoImpl3" class = "dao.UserDaoImpl" factory-method="getUserDao"/>
3.实例工厂 - <bean id ="daoFactory" class = "factory.DaoFactory"></bean>
<bean id="userDaoImpl4" factory-bean="daoFactory" factory-method="getUserDao"/>
依赖注入
a.set注入 <property name="属性名" ref="需要注入的对象bean组件的id">
b.构造方法注入<constructor-arg index="参数下标" ref="需要注入的对象bean组件的id"></constructor-arg>
各种类型的注入
通过表达式给bean组件属性赋值
-----------------------------------------------2019.9.25
AOP 是以面向对象为基础
AOP和OOP的区别
OOP主要是关注对象,如何抽象和封装对象
AOP关注切面 如何将多个业务中相同的步骤或者是行为进行封装,封装的低耦合的方式将方面组件作用到一批对象上
2.使用AOP的编程步骤
1.定义一个切入点 <aop:pointcut expression="表达式" id="切点"/>
2.配置切面<aop:aspect ref="切面组件ID">
3.定义通知<aop:after method="切面中的方法名字" pointcut="切点"/>
3.AOP相关概念
1.切面aspect
封装了相同的业务逻辑的组件,可以通过低耦合的方式
2.切入点pointcut
指定目标组件的表达式 可以用来指定切面组件与某一批组件的关系
3.连接点(joinpoint)
切入点就是连接点的集合,也是用来指定切面组件与一批组件的关系
4.通知advice
指定切面组件和目标组件执行的时机
5.目标
通过切入点指定的组件和方法
6.动态代理 auto proxy
AOP是基于动态代理技术实现的。在使用AOP之后,通过spring获取到的是动态代理类,该类继承目标组件的类型,重写了目标组件的方法,重写以后合并切面组件和目标组件方法。
动态代理实现的方式:
-1cglib 目标组件无接口
public 代理类 extends 源目标组件{
重写方法
}
-2jdk proxy api 目标组件有接口
public 代理类 implements 源目标组件接口{}
ps:jdk和cglib动态代理
a.如果目标对象实现了接口,则默认情况下用jdk动态代理去实现,没有接口,则使用cglib
b.如果目标对象实现了接口,可以强制使用cglib实现AOP
在配置文件中<aop:config proxy-target-class="true">
c.如果目标对象没有实现接口,则必须采用cglib
d.spring会自动在jdk动态代理和cglib之间切换
通知类型
前置通知 aop:before
后置通知 aop:after-returning 如果目标组件没有异常,则调用,如果有异常则不调用
异常通知 aop:after-throwing
最终通知 aop:after 不管目标组件是否有异常都可以看到
环绕通知 aop:around
try{
//前置通知
目标组件
//后置通知
}catch(){
异常通知
}finally{
最终通知
}
定义切入点表达式
1)方法限定表达式
execution(修饰符?返回类型?方法名(参数) 异常?)
-1 execution(public * *(..))匹配容器中所有的公共方法
-2 execution(* set*(..))任何一个名字以“set”开始的方法的执行:
-3 execution(* controller.UserAddController.*(..))
2)类型限定表达式
within(类型)
-1within(controller.*)
匹配controller包下所有类的所有方法
-2within(controller..*)
匹配controller包以及子包所有类的所有方法
3)名称限定表达式
bean(id值或者name值)
bean(addController)
匹配根据addController查找的bean组件对象中的所有方法
4)参数显示表达式
args(参数)
args(java.io.Serializable)
匹配容器中只有一个参数并且参数类型是符合serilizable的要求
spring注解
使用注解简化xml的配置,更方便管理bean组件,提高开发效率
使用注解的步骤
1.在spring配置文件中开启注解扫描器<context:component-scan base-package="需要扫描的组件" />
2.在需要管理的组件上使用注解标记
常用的注解 @Component 普通组件
@Service 业务组件
@Controller控制组件
@Repository数据仓库组件(持久层)
其他注解标记
-1.默认采用单例创建 可以使用@Scope("prototype") 改成原型模式
-2.单例默认是容器启动时实例化 可以使用@Lazy延迟实例化
-3.使用@PostConstruct指定初始化的方法@PreDestroy指定销毁前执行的方法
注:注解标记用在类上方 变量上方 方法上方
@Repository("usdao")或者@Repository(value="usdao")
IOC的注解
@Autowired 自动注入 dao = ac.getBean(UserDao)->ac.getBean("userDaoImpl")
private UserDao dao
@Autowired写在set方法上 表示spring容器通过读取xml配置返回一个bean,然后将其注入到成员变量中
解决一对一组件之间的调用
构造器注入就是在构造器上加@Autowired 属于spring技术 默认按照类型匹配,如果有多个符合需要使用@Qualifier("name")指明将某一个bean组件注入,@Qualifier("name")该注解可以用在变量set方法构造方法上面,但是不能放在构造方法的上面,只能放在构造方法参数的前面
----------------------------------------------------------------------- 20190926
@Autowired可以通过required=false 设置该变量允许为null
@Resource 默认按照名称匹配
属于JDK技术
默认按照变量名查找容器中的同名组件 若找不到,则按照变量类型查找,如果找到两个同类型的组件,可以通过@Resource(name=值)指定注入具体的组件
spring源码分析
public class Test03 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//准备创建message
Map<String, Object> map = new HashMap<String, Object>();
Class msgClazz = Message.class;
Class usClazz = User.class;
Message message = (Message) msgClazz.newInstance();
User user = (User)usClazz.newInstance();
//将对象放入map
map.put("user", user);
map.put("message", message);
System.out.println(message.getUser());
//容器会继续遍历 假设此时遍历到了message 发现在message有注解
//容器要再次利用反射创建对象
//获取某个类中所有声明的字段
Field[] field = msgClazz.getDeclaredFields();
for(Field f:field) {
if(f.isAnnotationPresent(Resource.class)) {
Object object = map.get(f.getName());
//修改私有变量的值
f.setAccessible(true);
//将f的值改成user
f.set(message, object);
}
}
System.out.println(message.getUser());
}
}
AOP注解
在spring中使用aop注解
1)在配置文件中启用aop注解
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
2)在切面组件中添加以下配置
-使用@Component将组件交给spirng容器管理
-使用@Aspect 将组件升级为切面组件
-使用@Pointcut定义切入点(若定义在方法上,此时方法名就是切入点名)
-使用@Around @Before @After @AfterReturning 定义通知
3.log4j日志记录工具
将异常信息打印到控制台或者保存到文件中
log4j,可以将信息按照级别以及格式输出到不同的区域
1)日志器
按级别输出日志
2)输出器
负责将信息写到指定区域
3)布局器
负责将信息按照不同的格式输出
spring对JDBC的支持
spring提供了数据库访问技术的支持 在spring平台访问数据代码量大大减少
优点:1)提供了对DataSupport的支持,jdbcDAOSupport类提供了对jdbcTemplate对象的获取,也可以获取连接对象。jdbcTemplate封装了增删改查方法
2)提供了统一的异常处理类,类型DataAccessException,该异常类封装了原jdbc抛出的异常。如sqlException,属于RuntimeException
如何将jdbcTemplate直接作为adminDaoImpl的属性,配置文件怎么写
---------------------------------------------------------------20190927
1.spring事务
什么是事务
事务是一系列动作,他们综合在一块就是一个完整的工作单元,这些动作必须都完成,只要有一个失败就要回滚
事务的特点:一致性 原子性 隔离性 持久性
spring事务
spring框架提供了事务的支持。spring提供了一个统一的编程接口 PlatformTractionManager.具体的事务管理机制由各个平台实现如jdbc或者hibernate mybatis
spring事务定义/事务属性
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,
它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:
REQUIRED
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类 似的操作。
事务的隔离性(mysql事务默认隔离级别可以解决脏读和不可重复读)
事务的隔离级别限定一个事务 受其他事务影响的程度,隔离级别越高受影响级别越小
脏读 一个事务读到了另一个事务未提交的数据
不可重复读 一个事务A读到了另一个事务B提交的数据(修改)ps事务A只有重新开才能读到事务B提交的数据
幻读一个事务读到了另一个事务提交的数据(侧重增加和删除)
mysql的事务隔离级别
read-uncommitted :读未提交 这个会导致脏读
read-committed:读已提交 解决脏读 但是会有不可重读的问题
repeated-red:可以重复读 可以重复读的意思是一个事务中重复读取得到数据是一致的 mysql的默认隔离级别,会出现幻读(A事务开启 不关闭b事务新增一条数据后提交,此时A数据是看不到的,由于没有看到,当修改数据,可能会修改b事务操作的数据)
serializable:串行化 解决了三个问题,但是效率比较低
mysql的事务隔离级别
isolation-default:默认采用数据库的隔离级别
isolation-read-uncommitted :读未提交 这个会导致脏读
isolation-read-committed:读已提交 解决脏读 但是会有不可重读的问题
isolation-repeated-red:可以重复读 可以重复读的意思是一个事务中重复读取得到数据是一致的 mysql的默认隔离级别,会出现幻读(A事务开启 不关闭b事务新增一条数据后提交,此时A数据是看不到的,由于没有看到,当修改数据,可能会修改b事务操作的数据)
isolation-serializable:串行化 解决了三个问题,但是效率比较低
事务的超时
相当于一个定时器,当超过定时的时间,事务会自动回滚
事务只读
如果事务只对数据进行读取操作,可以设置事务只读,从而实现优化
spring管理事务
编程式管理事务 -用的较少 缺点:侵入性较强
声明式管理事务 -侵入性较低 基于aop将事务配置到作用的目标上,代码的侵入性较低
基于xml配置
-1.步骤一:定义事务管理器
<bean id="txTransactionManage" class="spring的管理器路径">
<property name="dataSource" ref="连接池id">
</bean>
-2.步骤二:定义事务声明及策略
<tx:advice id="事务建议id" transactionManager="txTransactionManage">
<tx:attributes >
<tx:method name="启用事务的方法名称" propagation="事务传播方式"/>
</tx:attributes >
</tx:advice>
-3.步骤三:通过aop配置将事务机制作用到一批组件上
<aop:config>
<aop:advisor advice-ref="事务建议id" pointcut="切入点表达式"
</aop:config>
基于注解
-step1:定义事务管理器
<bean id="管理器名称" class="spring的管理器路径">
<property name="dataSource" ref="连接池id">
</bean>
-step2:启动组件扫描
<context:component-scan base-package="com.xms"></context:component-scan>
-step3:在目标组件上添加注解及策略
-step4:启用事务aop注解
<tx:annotation-driven transaction-manager="管理器名称"/>
springmvc
springmvc是一个轻量级的mvc框架,便于快速高效的开发一个web应用
springmvc体系结构
-a.dispatcherServlet 转发处理器
-b.handlerMapping 映射处理器
-c.controller控制器
-d.ModelView:模型与视图
-e.ViewResolver:视图解析器
---------------------------------------------------------20190928
mvc分层思想
M(Model)模型层:封装以及处理数据 entity dao service
V(View)视图层:收集及展示数据 jsp
C(Controller) 控制层:负责协调M和V ActionServlet filter
mvc是软件架构中的一种设计思想,按照代码功能划分为三个模块 分别是视图模型控制器,模型处理之后的结果不会直接返回给视图,而是经过控制器,由控制器返回给视图。同理视图的请求也不会直接能够去调用模型,而是由控制器调用模型方法处理
实现模型的复用
模型与视图的其中一方发生概率比那,都不会影响另一方
方便测试
springmvc处理请求流程
1.请求发起后交给dispatcherServlet(前端控制器),
2.控制器通过handlermapper查找controller组件
3.执行controller组件中约定的方法,在方法中调用模型处理器并将结果封装到ModelAndView对象中,方法结束后,返回该对象
4.Controller接收到ModelAndView,调用视图解析器,解析该对象中的视图信息,定位到具体的资源路径,将文件返回给用户
web-inf浏览器不可以直接访问的
xml配置
1.定义业务控制器实现controller接口
重写handlerequest返回MAV对象
2.web.xml中配置前端控制器dispatcherServlet
*-配置初始化参数,指定spring配置文件的查找路径
*-配置容器启动时实例化控制器
3.定义spring配置文件(applicationContext.xml)
*-定义bean组件的管理(业务控制器)
*-配置映射处理器(HandleMapping),指定请求地址和业务处理器的关系
*-配置视图解析器,根据MAV对象的视图名称解析成视图资源文件
基于注解
-1定义业务控制器,在其中使用注解@Controller
使用@RequestMapping(请求名)配置映射关系
-2web.xml中配置前端控制器dispatcherServlet
*-配置初始化参数,指定spring配置文件的查找路径
*-配置容器启动时实例化控制器
-3定义spring配置文件(applicationContext.xml)
*-配置视图解析器,根据MAV对象的视图名称解析成视图资源文件
开启组件扫描
开启springmvc注解
参数传递
1)后台获取页面传入的参数
*-httpservletrequest 缺点:必须手动调用方法req.getParameter("参数名") 要手动转换数据类型
2)通过形参接收数据
*-默认形参名称和参数名一致
*-若传入的参数名和形参名不一致可以通过@RequestParameter(参数名)指定两者对应关系
*-可以直接定义对象接收页面传入的属性值 属性值必须要有set方法
3)页面接收后台返回的数据
-1通过HttpServletRequest绑定数据
-2通过Map传递 -一定要将map放到ModelAndView
-3通过ModelMap 传递
-4通过@ModelAttribute传参
重定向
-1通过ModelAndView(new RedirectView("地址"))
ModelAndView modelAndView = new ModelAndView("redirect:test8.do");
ModelAndView modelAndView = new ModelAndView("test8.do");转发
----------------------------------------------------20190929
页面传入数据中文乱码
*-配置过滤器
spring对ajax的支持
为了更好的接收和处理ajax请求,spring提供了对ajax支持,可以方便的将后台数据转换成json字符串,返回给请求发起端
spring处理异常
处理异常的原则:尽量底层处理 处理不了往上抛异常
处理的方式:
1.利用SimpleMappingExceptionResolver
<property name="defaultErrorView" value="error1"></property>
<property name="exceptionMappings">
<props>
<prop key="java.lang.NumberFormatException">error1</prop>
</props>
</property>
2.利用实现HandlerExceptionResolver重写resolveException方法
3.在控制器中写
@ExceptionHandler
public String resolveException(Exception ex,HttpServletRequest request) {
return "error1";
}
完成登录页面的验证码显示及校验
验证码正确时才可以提交登录请求
----------------------------------
1.拦截器
如何定义一个拦截器
1)定义java类 实现HandlerInterceptor接口
2)重写方法
3)配置文件 applicationContext
主要是实现HandlerInterceptor接口,handlermapping支持拦截器的调用可以拦截controller请求,拦截器适合封装通用的处理,如session验证
过滤器:依赖于web容器,而且过滤器基于函数回调
拦截器:依赖spring框架,基于类的反射实现
AOP:拦截器是在请求到达控制器之前起作用,而AOP在请求到达控制器之后起作用,而且拦截器只能拦截controller,而AOP可以对各种bean组件起作用
----------------------------------------------mybatis
Mybatis
支持普通sql查询,存储过程和高级映射的优秀持久层框架,其使用简单的xml配置或者是注解配置,来定义映射关系,将实体类对象映射成数据库表中的记录
Mybatis工作原理
1)加载配置
mybatis将sql的映射加载为一个个的MappedStatement对象(包括传入的参数映射配置,执行的SQL语句,结果映射配置),将其存储在内存中
2)sql解析
当调用api接收到调用请求时候,会接收到传入的SQL的ID和传入的参数对象(可以是Map,实体类对象或者是基本数据类型),Mybatis框架会根据SQL的id找到相对应的MappedStatement,然后根据传入的参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数
3)SQL执行
将最终得到的sql语句和参数拿到数据库进行执行,得到执行结果
4)结果映射
将操作数据库的结果按照上面的结果映射配置进行转换,可以转换为Map集合,实体类,基本数据类型,将最终转换结果返回
Mybatis框架API组件
SQLsessionfactoryBuilder此组件负责根据Mybatis主配置文件来构建sqlsessionfactory
sqlsessionfactory每一个mybatis的应用程序都以一个sqlsessionfactory对象为核心每一个,因为此组件负责创建sqlsession对象
sqlsession:此组件包含所有执行sql语句操作的方法,用于执行已经映射的sql语句
mybatis的配置文件
1)sqlmapconfig.xml(1个)
主配置文件,用于指定数据库连接参数信息和框架信息
2)sqlmapper.xml(N个)映射文件,用于定义sql语句的映射信息
mybatis的基本操作
1)搭建mybatis的技术环境
为工程添加mybatis的开发包和数据库的驱动包
在src下添加mybatis的主配置文件sqlmapconfig.xml
配置sqlmapconfig.xml,指定数据库连接参数和框架参数
利用mybatis提供的API,获取sqlsession对象
获取sqlsession对象 String path="主配置文件的url";
Reader reader = Resources.getResourceAsReader(path);
//构建sqlsessionfactory对象
SQLsessionfactoryBuilder ssfb = new SQLsessionfactoryBuilder()
sqlsessionfactory ssf = ssfb.build(reader);
//构建Sqlsession对象 这个对象用于执行已经映射的sql语句
SqlSession ss = ssf.openSession();
3)利用sqlsession实现CRUD操作(create retrieve读取查询 update delete)
根据数据库的表编写实体类
编写sqlmapper.xml映射文件,定义sql操作和映射信息
获取sqlsession对象,执行增删改查操作
提交事务(DML)
释放sqlsession对象资源
实例操作
use test;
员工表
create table emp(
empno int(4) primary key auto_increment,
ename varchar(10) not null,
salary double(7,2),
bonus double(5,2),
hiredate date,
deptno int(2)
);
insert into emp values(1001,'张三',33333.33,333.33,now(),1);
insert into emp values(1002,'李四',44444.44,444.44,now(),2);
insert into emp values(1003,'王五',55555.55,555.55,now(),3);
insert into emp values(1004,'赵六',66666.66,666.66,now(),4);
部门表
create table dept(deptno int primary key auto_increment,
dname varchar(10) not null);
insert into dept values(1,'研发部');
insert into dept values(2,'财务部');
insert into dept values(3,'行政部');
---------------------------------------------
1.优化mybatis配置文件中的配置
1)连接数据库的配置
第一种方式
<!-- 定义属性 -->
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</properties>
<environments default="develop">
<environment id="develop">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xms/entity/DeptMapper.xml"/>
</mappers>
第二种方式
推荐使用
<configuration>
<!-- 定义属性 -->
<!-- <properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</properties> -->
<!-- 引入外部的属性 -->
<properties resource="db.properties"></properties>
<environments default="develop">
<environment id="develop">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xms/entity/DeptMapper.xml"/>
</mappers>
</configuration>
2)为实体类等定义别名,简化映射文件中的引用
问题:映射文件中,引用实体类时候,需要指定实体类的全类名(包名+类名),如下resultType="com.xms.entity.Dept"
通过在mybatis的配置文件,注意是配置文件不是映射文件,中指定别名
<configuration>
<!-- 定义属性 -->
<!-- <properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</properties> -->
<!-- 引入外部的属性 -->
<properties resource="db.properties"></properties>
<!-- 指定单个类型
<typeAliases>
<typeAlias type="com.xms.entity.Dept" alias="_Dept"/>
</typeAliases>
-->
<!-- 指定类型别名包,别名默认为类名 -->
<typeAliases>
<package name="com.xms.entity"/>
</typeAliases>
<environments default="develop">
<environment id="develop">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xms/entity/DeptMapper.xml"/>
</mappers>
</configuration>
小知识点
resultType="java.util.Map" 可以写成map但是map要小写这个是mybatis中的类型
二.Mybatis基本操作
1)返回Map类型的查询结果
根据员工号要查询员工信息同时查询出员工所在的部门信息
select e.*,d.* from emp e join dept d
2)解决字段名与实体类属性名不一致
注意:不一致问题,如果结果集的字段名和实体类的属性名全部不一致,且在结果映射时定义为resultType,则不会创建实体对象的,但是如果只是部分不一致,则会创建实体对象并且自动关联属性名和字段名一致的属性
通过在查询的sql语句中,定义字段名的别名,将字段名和实体类的属性名一致
通过resultMap来映射字段名和实体类属性名的一一对应关系,Mybatis提供的解决方式,进行关联
3)Mapper映射接口
mapper映射接口是开发者创建用于绑定映射语句的接口,这个映射接口的实例对象(这个实例对象是代理类对象)可以从sqlsession中获取
注意:映射文件中namespace的值必须与对应的Mapper接口的名称一致
映射文件中sql的id必须与对应Mapper接口中的方法名一致
4)注解方式实现CRUD
-------------------------------------------Mybatis
mybatis动态sql
动态sql是mybatis框架中特性之一,在一些组合查询页面需要根据用户输入的条件的不同生成不同的查询sql语句,在JDBC或其他相似框架中需要在代码中拼接sql语句,容器出错,Mybatis框架动态生成sql可以根据条件的不同来生成不同的sql语句
动态sql标签与jstl标签相似,它允许在xml中构建不同的sql语句,常用的sql标签如下:
判断标签if,choose(when,otherwise)
关键字标签 where,trim,set
循环标签:foreach
if标签是简单的条件判断逻辑,满足指定条件时,追加if标签中的sql语句,如果不满足,就不追加,使用格式
<select>
<if test="条件表达式">
sql语句2
</if>
</select>
if标签最常见的使用在where子句部分,根据不同的情况追加不同的sql语句
choose标签的作用相当于java的switch语句,基本上跟jstl中choose的作用和用法是一致的,通常与when和otherwise搭配使用,使用格式如下:
<select>
sql语句1
<choose>
<when test="条件表达式">
sql语句2
</when>
<when test="条件表达式">
sql语句3
</when>
<otherwise>
sql语句4
</otherwise>
</choose>
</select>
where标签可以在<where>标签所在的位置输出一个where关键字,而且可以将后面多余的and或者or关键字取出,使用格式如下:
<select>
select * from emp
<where>
<if test="deptno !=null">
deptno = #{deptno}
</if>
<if test="salary != null">
and salary > #{salary}
</if>
</where>
</select>
set标签主要是用在更新操作时,它的主要功能和where标签相似,主要是在<set>标签所在的位置输出一个set关键字,而且还可以取出内容结尾无关的逗号
<update>
update emp
<set>
<if test="ename != null ">
ename = #{ename},
</if>
<if test="salary != null ">
salary = #{salary},
</if>
<if test="hiredate != null ">
hiredate = #{hiredate}
</if>
</set>
</update>
trim标签主要功能如下:
1)可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性时prefix和suffix
2)可以把包含内容收不的某些内容过滤,即忽略,也可以把稳步的某些内容过滤,对应的属性是prefixOverrides和suffixOverrides
<!-- 等价于where -->
<trim prefix="where" prefixOverrides="and|or">
.....
</trim>
<!-- 等价于set -->
<trim prefix="set" suffixOverrides=",">
......
</trim>
foreach标签实现循环逻辑,可以进行一个集合迭代,主要用在构建IN条件中,使用格式如下
select * from emp where empno in(1001,1003,1005);
<select>
select * from emp where empno in
<foreach collection="集合" item="迭代变量" open="(" close=")" separator=",">
#{迭代变量}
</foreach>
</select>
insert into dept values(1,"研发部"),(2,"财务部"),(3,"行政部"),(4,"市场部")
<insert>
insert into dept values
<foreach collection="depts" item="dept" separator=",">
(#{dept.deptno},#{dept.dname})
</foreach>
</insert>
foreach标签允许指定一个集合,声明集合项和索引变量,变量可以用在标签体内,它允许指定开放和关闭字符串,在迭代项之间放置分隔符
bind标签可以从OGNL表达式中创建一个变量并将其绑定到上下文,使用格式如下:
select * from emp where ename like '%三%'
select * from emp where ename like concat('%',#{ename},'%')
注意:Oracle数据库中concat函数有且仅有两个参数,即需要嵌套调用concat(concat('%',#{ename}),'%')
<select id="" parameterType="Condition">
<bind name="enameLike" value="'%'+ename+'%'">
select * from emp where ename like #{enameLike}
</select>
特殊字符
在XML文件中处理特殊符号
第一种方式:采用XML转义字符 < <
> >
& &
' '
" "
空格
第二种方式:采用<![CDATA[]]>进行说明,将此内容不进行解析
<if test="">
and salary <![CDATA[<]]> 50000.0
</if>
#{}与${}
1.都是取变量的值
2.#{}取值时sql语句中变量的值会替换成?(占位符),${}直接替换成变量的值,#{}处理是安全的,即可以防止SQL注入,且是预编译
3.${}方式一般用于传入数据对象,例如:表明,字段名
提醒:能用#{}的时候就别用${}
select * from emp order by 'salary' desc;
这种写法是错误的,但是不会报错,会全部查询出结果并且正序排列,因此这个'salary'地方不能用#{salary},而要用${salary}
#{}会将该出添加一个占位符,然后 查询时候加上''
举个例子
select * from emp where empno = #{empno};
||
\/
select * from emp where empno = '1003'而不是select * from emp where empno = 1003
注意:string类型字符串可以自动转换成其他任意类型,但是其他类型相互之间是不可以相互转换的
举个例子
select * from emp where hiredate = '2019-10-09';这个查询是没有问题的 hiredate是date类型
select * from emp where hiredate = 2019-10-09;这个查询就会查不到
回顾:
jsp九大内置对象
页面四大作用域 pageContext request session application
jsp三个指令 include taglib import
jsp6个动作
include:include行为用于运行时包含某个文件,如果被包含的文件为jsp程序,则先会执行JSP程序,然后把执行的结果包含进来,作用跟include一样
java Bean行为{
userBean行为 <jsp:userBean id="beanObject" class="className" scope="Value">
}
--------------------------------------------------2019.10.14
1.MyBatis关联映射
1)主键映射
在插入操作时,返回自动递增的主键值
MySQL(数据库支持自动递增)
<insert id="" parameterType="Dept" useGeneratedKeys="true" keyProperty="deptno">
insert into dept values(null,#{dname})----#{} 多个时候,里面的值不能随便填写
</insert>
在insert标签指定自动递增属性设置后,Mybatis框架会在插入操作后将自动递增生成的主键值给keyProperty指定的属性进行赋值
Mybatis的关联映射有两种不同形式的实现形式:
1.嵌套查询:通过执行另一个SQL映射语句来返回关联数据(简单来说就是查询两次)
2.嵌套结果查询:执行一个表关联查询SQL语句,然后将查询结果映射成关联对象(查询一次)
2)一对一映射
use test;
create table teacher(t_id int(4) primary key auto_increment,
t_name varchar(10));
create table class(c_id int(2) primary key auto_increment,
c_name varchar(20),
teacher_id int(4));
alter table class add constraint fk_teacher_id foreign key(teacher_id) references teacher(t_id);
insert into teacher(t_name) values('张三丰');
insert into teacher(t_name) values('孙悟空');
insert into class(c_name,teacher_id) values ('三年二班',2);
insert into class(c_name,teacher_id) values ('五年六班',1);
<!-- 一对一嵌套查询 -->
<select id="findTeacherByIdOne" parameterType="integer" resultMap="teacherMapOne">
select * from teacher where t_id = #{456456456}
</select>
<resultMap type="Teacher" id="teacherMapOne">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
<association property="clazz" column="t_id" select="findClass"/>
</resultMap>
<select id="findClass" parameterType="integer" resultMap="classMap">
select * from class where teacher_id =#{123123132}
</select>
<resultMap type="Clazz" id="classMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<result property="teacherId" column="teacher_id"/>
</resultMap>
<!-- 一对一嵌套结果查询 -->
<select id="findTeacherByIdTwo" parameterType="integer" resultMap="teacherMapTwo">
select t.*,c.* from teacher t join class c on t.t_id=c.teacher_id where t.t_id =#{id}
</select>
<resultMap type="Teacher" id="teacherMapTwo">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
<association property="clazz" column="t_id" javaType="Clazz"> --Clazz是实例化的一个对象
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<result property="teacherId" column="teacher_id"/>
</association>
</resultMap>
3)一对多映射
嵌套结果查询时候,结果集中的字段名和实体类中的属性名没有自动关联
<!-- 一对多的嵌套结果查询 -->
<select id="findDeptByDeptnoTwo" parameterType="integer" resultMap="deptMapTwo">
select d.*,e.* from dept d join emp e on d.deptno = e.deptno where d.deptno = #{12123}
</select>
<resultMap type="Dept" id="deptMapTwo" autoMapping="true">
<id property="deptno" column="deptno"/> ---这里添加一个主表的结果集映射的时候,会检测主表中的数据避免下面的问题
<collection property="emps" javaType="java.util.ArrayList" ofType="Emp" column="deptno" autoMapping="true">
</collection>
</resultMap>
注意:
问题:主表中返回字段是Dept对象,那么mybatis默认就会调用selectOne方法,但是发现查询结果居然有两条数据,这个时候,就会报错
解决方法:通过在结果集中手动加入一个映射属性,这样就会调用selectList方法
4)多对一映射
其实就是一对一 刚检测了一下凡是嵌套结果查询的时候,如果属性名和表中字段名一致都是不会自动映射的要通过属性进行打开
4)多对多映射
create table student(s_id int(4) primary key auto_increment,s_name varchar(10) not null);
create table course(c_id int(4) primary key auto_increment,c_name varchar(10) not null);
create table student_course(
student_id int(4),course_id int(4));
insert into student(s_name) values ('张三'),('李四'),('王五'),('赵六');
insert into course (c_name) values ('语文'),('数学'),('英语');
insert into student_course values(1,1),(1,3),(2,1),(2,2),(2,3),(3,2),(3,3),(4,1),(4,2);