1.Filter
1.1.过滤器概念
1.1.1.过滤器的基本概念
Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
1.1.2.过滤器的功能
如图-1所示:
— 可选的 可以配置多个 过滤器的初始化参数 可以在过滤器中通过FilterConfig对象来获取
name1
value1
— 配置过滤器的拦截路径 ,一个可以配置多个
FirstFilter
—为哪个过滤器进行配置
/*
— 拦截哪个路径 其中url-pattern的写法和学习Serlvet时的url-pattern的写法相同 这个url-pattern可以配置多个
Demo1Servlet
—拦截哪个名字的Servlet 可以配置多个
REQUEST
— 配置拦截哪种类型的对资源的访问,可选的值有REQUEST FORWARD INCLUDE ERROR,如果不配置默认只拦截REQUEST方式,如果具体配置了就拦截具体配置的方式的对资源的访问,此标签可以配置多个
1.3.Filter的生命周期
1.3.1.Filter的生命周期
当服务器启动,web应用加载后,立即创建出这个web应用中的所有过滤器对象,创建出来后立即调用过滤器的init方法执行初始化操作.从此这些过滤器对象驻留在内存中为后续的拦截进行服务.每当拦截到资源时,都会导致dofilter方法执行.最终直到服务器关闭或web应用移除出容器时,随着web应用的销毁,过滤器对象销毁,销毁之前调用destory方法执行善后工作。
1.4.FilterConfig接口
1.4.1.Filterconfig接口
用户在配置filter时,可以使用为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。
1.4.2.Filterconfig接口提供的方法
FilterConfig提供的方法:
String getFilterName():得到filter的名称。
String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
public ServletContext getServletContext():返回Servlet上下文对象的引用。
1.5.EasyMall全站乱码解决过滤器
1.5.1.全站乱码过滤器
我们可以开发一个Filter,拦截所有的动态web资源,在动态web资源执行之前,解决好乱码,从而一劳永逸的解决全站乱码问题。
对于响应数据乱码,只需要设置Content-Type即可解决乱码。
对于请求参数乱码,如果是POST提交,可以一行代码解决,如果是GET提交需要手动的编解码解决乱码。
1.5.2.代码实现
如图-3所示:
自动登录过滤器
AutologinFilter
com.itheima.filter.AutologinFilter
AutologinFilter
/
1.7.MD5
1.7.1.MD5概述
用户名密码保存在客户端是一种十分危险的行为。所以需要进行加密后保存。
其中MD5就是一种比较常用的加密算法。
与其说MD5算法是一种加密算法,不如说是一种数据指纹(数据摘要)算法。
其特点如下:
任意大小的二进制数经过MD5计算后都能得到一个独一无二的128位二进制数。
不同的数据算出的MD5绝对不相同。
相同的数据算出的MD5一定相同。
只能有明文算出密文,密文是永远也无法算成明文的。
MD5大量应用于计算机中。如数据库中保存的密码通常都是经过MD5加密后的数据。如用户下载文件时可以进行MD5校验防止数据被篡改。
在记住用户名案例中,我们可以使用MD5进行加密后再保存在客户端,从而保证数据安全。
在数据库中保存的密码也不宜直接存储为明文。也要经过MD5加密后存储。
1.7.2.JAVA实现MD5加密
/**
* 使用md5的算法进行加密
*/
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance(“md5”).digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(“没有md5这个算法!”);
}
String md5code = new BigInteger(1, secretBytes).toString(16);
for (int i = 0; i < 32 – md5code.length(); i++) {
md5code = “0” + md5code;
}
return md5code;
}
1.Listener
1.1.1.Servlet监听器概述
1.1.1.1.Servlet监听器概述
JavaEE中提供了八大监听器,用来监听Servlet中指定事件。
1.1.2.Servlet事件监听器步骤
实现web开发中的事件监听功能需要两个步骤:
(1)写一个类实现对应接口。
(2)在将写好的监听器类注册到web.xml中。
1.1.1.1.2.监听三个作用域对象创建和销毁的监听器
1.2.1.2.1.ServletContextListener 详解
ServletContextListener 监听器用于监听 ServletContext 对象的创建和销毁。
ServletContext域的生命周期:
服务器启动,web应用加载后,立即创建代表当前web应用的ServletContext对象,从此驻留在内存中,直到服务器关闭或web应用被移除出容器时,ServletContext对象被销毁。
1.2.2.HttpSessionListener详解
HttpSessionListener监听器用于监听HttpSession对象的创建和销毁。
HttpSession域的生命周期:
在第一次调用request.getSession()方法时创建。
超时过30分钟没人用(此时间可以在web.xml中修改)被销毁。
调用session.invalidate()方法被销毁。
服务器非正常关闭时销毁。
那么,当如果服务器是正常关闭,session会如何处置呢br> 未超时的session会以文件的形式保存在服务器中,这个过程叫做session的钝化。在下一次服务器正常启动时,session还可以恢复回来,这个过程叫做session的活化。
*注意:想要随着session被钝化(活化)的对象,他的类必须实现Serializable接口。
作用范围:整个会话范围。
1.2.3.ServletRequestListener 详解
ServletRequestListener监听器用于监听ServletRequest对象的创建和销毁。
ServletRequest对象的生命周期:
请求开始,服务器创建代表这次请求的reuqest对象.
请求结束,服务器销毁代表请求的request对象。
1.1.1.1.2.1.3.监听域属性变化的监听器
1.3.1.监听域属性变化的监听器
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。
1.3.2.监听域属性变化的监听器中的方法
(1)attributeAdded 方法
当向被监听器对象中增加一个属性时,web容器就调用事件监听器的 attributeAdded 方法进行相应,这个方法接受一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象。
(2)attributeRemoved 方法
当删除被监听对象中的一个属性时,web 容器调用事件监听器的这个方法进行相应。
(3)attributeReplaced 方法
当监听器的域对象中的某个属性被替换时,web容器调用事件监听器的这个方法进行相应。
1.2.2.1.2.2.2.3.1.4.监听JAVABEAN在Session域中状态变化的监听器
1.4.1.Javabean在Session中的状态
保存在 Session 域中的对象可以有多种状态:
(1)绑定到 Session 中。
(2)从Session 域中解除绑定。
(3)随Session 被钝化
(4)随Session被活化
1.4.2.监听JAVABEAN在Session域中状态变化的监听器
Servlet 规范中定义了两个特殊的监听器来使javabean感知自己在Session域中状态的变化:
(1)HttpSessionBindingListener接口
实现了HttpSessionBindingListener接口的 JavaBean 对象可以感知自己被绑定到 Session 中和从 Session 中删除的事件。
//当对象被绑定到 HttpSession 对象中时触发
void valueBound(HttpSessionBindingEvent event)
//当对象从 HttpSession 对象中解除绑定时触发
void valueUnbound(HttpSessionBindingEvent event)
(2)HttpSessionActivationListener接口
实现了HttpSessionActivationListener接口的 JavaBean 对象可以感知自己被活化和钝化的事件。
//当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被钝化时触发
sessionWillPassivate(HttpSessionBindingEvent event)
//当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被活化时触发
void sessionDidActive(HttpSessionBindingEvent event)方法。
2.文件上传
1.2.2.1.文件上传概述
1.2.2.1.2.1.1.文件上传是什么
在web开发中经常需要从客户端向服务器上传文件,如:上传照片、上传新闻图片、上传附件等等。这些都需要通过WEB开发中的文件上传技术实现。
1.1.1.1.2.1.2.文件上传步骤
实现web开发中的文件上传功能只需要两个步骤:
(1)提供一个带有文件上传项的表单。
(2)在servlet中读取处理上传的文件,保存到服务器中。
1.2.2.1.2.2.文件上传实现
2.2.2.2.1.在用户页面中添加上传输入项 (客户端页面操作)
注意事项:
(1) 必须为文件上传input 提供name属性,否则文件上传内容不会被表单提交
(2) 表单的提交方式必须为post (get提交数据在url地址上显示,有长度限制)
(3) 表单必须设置enctype=multipart/form-data
1.1.1.1.2.1.2.1.2.2.2.在服务器端编写文件上传程序
通过Request对象提供的一个getInputStream方法,可以读取到客户端提交过来的数据,但这种方式还需要对流中获取到的数据进行处理。
为了简化这个处理过程,Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件(Commons-fileupload ),让开发人员轻松实现web文件上传功能。
2.2.3.上传组件(Apache commons-fileupload)使用过程
首先需要下载并导入该组件相应的支撑jar包: Commons-fileupload和commons-io
然后编程实现,步骤如下:
(1)创建DiskFileItemFactory对象,设置缓冲区大小和临时文件目录。
public DiskFileItemFactory(int sizeThreshold, java.io.File repository)
构造工厂时,指定内存缓冲区大小和临时文件存放位置。
public void setSizeThreshold(int sizeThreshold)
设置内存缓冲区大小,默认10K。
public void setRepository(java.io.File repository)
设置临时文件存放位置,默认System.getProperty(“java.io.tmpdir”)。
内存缓冲区: 上传文件时,上传文件的内容优先保存在内存缓冲区中,当上传文件大小超过缓冲区大小,就会在服务器端产生临时文件
临时文件存放位置: 保存超过了内存缓冲区大小上传文件而产生临时文件
- 产生临时文件可以通过 FileItem的delete方法删除
(2)使用DiskFileItemFactory 对象创建ServletFileUpload对象,并设置上传文件的大小限制。
(3)调用ServletFileUpload.parseRequest方法解析request对象,得到一个保存了所有上传内容的List对象。
ServletFileUpload 负责处理上传的文件数据,并将表单中每个输入项封装成一个 FileItem 对象中。常用方法有:
//判断上传表单是否为multipart/form-data类型。
boolean isMultipartContent(HttpServletRequest request)
//解析request对象,并把表单中的每一个输入项包装成一个fileItem 对象,并返回一个保存了所有FileItem的list集合。
List parseRequest(HttpServletRequest request)
//设置单个上传文件的最大值。
setFileSizeMax(long fileSizeMax)
//设置上传文件总量的最大值。
setSizeMax(long sizeMax)
//解决上传文件名乱码问题。
setHeaderEncoding(java.lang.String encoding)
//实时监听文件上传状态。
setProgressListener(ProgressListener pListener)
(4)对list进行迭代,每迭代一个FileItem对象,调用其isFormField方法判断是否是上传文件。
True 为普通表单字段,则调用getFieldName、getString方法得到字段名和字段值
False 为上传文件项,则调用getInputStream方法得到数据输入流,从而读取上传数据。
(5)如果是文件上传就通过流获取上传的数据保存到服务器中。
boolean isFormField() 判断FileItem是一个文件上传对象还是普通表单对象
普通字段项:
String getFieldName() 获得普通表单对象的name属性
String getString(String encoding) 获得普通表单对象的value属性,可以用encoding进行编码设置
文件上传项:
String getName() 获得上传文件的文件名(有些浏览器会携带客户端路径)
InputStream getInputStream() 获得上传文件的输入流
delete() 在关闭FileItem输入流后,删除临时文件
3.3.1.3.2.3.3.上传文件的监听
1.2.2.1.2.2.2.2.1.2.2.2.3.2.3.1.上传文件的监听
ServletFileUpload类提供了如下方法,监听文件上传时的进度信息:
public void setProgressListener(ProgressListener pListener)
设置监听器,文件上传程序会自动执行,监听器中 update方法
public void update(long pBytesRead, long pContentLength, int pItems)
在方法中可以获得 文件总大小、已经上传大小和 上传第几个元素
能否根据上面三个参数计算:剩余大小、传输速度、已用时间、剩余时间
(1) 已用时间 = 当前时间 – 开始时间
(2) 速度 = 已经上传大小/已用时间
(3) 剩余大小 = 总大小- 已经上传大小
(4) 剩余时间 = 剩余大小/速度
3.4.上传文件注意问题
2.4.2.4.1.文件保存的位置
上传的文件如果直接存放在web应用根目录下,通过浏览器是可以直接访问的,如果用户上传一个JSP,再通过浏览器访问就可以通过文件上传在服务器执行任意的java代码,十分危险。
所以一定要注意,文件上传服务器保存文件的位置必须是WEB-INF目录下或服务器中浏览器无法访问的位置。
2.4.2.防止上传的文件重名覆盖
上传的文件如果重名,后上传的文件就会覆盖先上传文件 。
为了防止这样的问题产生,应该对文件名进行处理,可以在文件名前拼接UUID,防止文件名重复。
filename = UUID.randomUUID().toString() + “_” + filename;
2.4.3.防止同一个目录下上传文件过多
一个目录下如果文件过多,必然会导致访问效率下降。所以我们需要将上传的文件进行分目录存储。
分目录存储的算法可以有很多:
(1) 按照上传时间进行目录分离 (周、月 )
(2) 按照上传用户进行目录分离 —– 为每个用户建立单独目录
(3) 按照固定数量进行目录分离 —— 假设每个目录只能存放3000个文件 ,每当一个目录存满3000个文件后,创建一个新的目录
(4) 按照唯一文件名的hashcode 进行目录分离
public static String generateRandomDir(String uuidFileName) {
// 获得唯一文件名的hashcode
int hashcode = uuidFileName.hashCode();
// 获得一级目录
int d1 = hashcode & 0xf;
// 获得二级目录
int d2 = (hashcode >>> 4) & 0xf;
return “/” + d2 + “/” + d1;// 共有256目录
}
2.4.4.文件上传代码实现
1.会话技术
1.1.会话技术
1.1.1.会话概述
会话可简单理解为:用户开一个浏览器,访问多个资源,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
1.1.2.会话中的问题
每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,程序要想办法为每个用户保存这些数据。
如用户登录过后,应该保存一个用户状态,在会话结束前表明用户一直是登录状态。并且不同的用户之间的登录状态应该互不影响。
我们之前已经学过request域和SerlvetContext域,我们分别分析一下。
Request域太小了,在多次请求中,每次请求响应都是新的Request对象,之前存入的request域中的域属性,在请求结束后随着request域的销毁而消失了。
ServletContext域太大了,所有用户都在操作这个域,必然会发生混乱。
此时我们需要会话相关的技术,保存会话产生的数据。
图-8
2.Cookie技术
2.1.Cookie技术
2.1.1.Cookie概述
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。如图-9所示:
“//user[@username=’”+username+”’ and @password=’”+password+”’]”
);
if(ele == null){
//没有找到,提示用户名密码不正确
response.getWriter().write(“用户名密码不正确!”);
return;
}else{
//用户名密码正确,将用户名保存到session中表明用户登录过
request.getSession().setAttribute(“user”, username);
//检查用户是否勾选过记住用户名
if(“true”.equals(request.getParameter(“remname”))){
//发送cookie保存用户名
Cookie remnamec = new Cookie(“remname”,username);
remnamec.setPath(“/”);
remnamec.setMaxAge(36002430);
response.addCookie(remnamec);
}
//回到主页
response.sendRedirect(“/index.jsp”);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
经过测试,发现当用户勾选过记住用户名时,会发送cookie给浏览器保存用户名。如图-11所示:
1.事务
1.1.事务的概念
1.1.1.事务的概念
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
例如:A——B转帐,对应于如下两条sql语句
update account set money=money-100 where name=‘a’;
update account set money=money+100 where name=‘b’;
1.2.管理事务
1.2.1.数据库默认的事务
数据库默认支持事务的,但是数据库默认的事务是一条sql语句独占一个事务,这种模式,意义不大.
1.2.2.手动控制事务
如果希望自己控制事务也是可以的:
start transaction;
– 开启事务,在这条语句之后的所有的sql将处在同一事务中,要么同时完成要么同时不完成
…
–事务中的sql在执行时,并没有真正修改数据库中的数据
commit;
– 提交事务,将整个事务对数据库的影响一起发生
rollback;
– 回滚事务,将这个事务对数据库的影响取消掉
1.2.3.JDBC中控制事务
当Jdbc程序向数据库获得一个Connection对象时,默认情况下这个Connection对象会自动向数据库提交在它上面发送的SQL语句。若想关闭这种默认提交方式,让多条SQL在一个事务中执行,可使用下列语句:
conn.setAutoCommit(false);
–关闭自动连接后,conn将不会帮我们提交事务,在这个连接上执行的所有sql语句将处在同一事务中,需要我们是手动的进行提交或回滚
conn.commit();
–提交事务
conn.rollback();
–回滚事务
也可以设置回滚点回滚部分事务。
SavePoint sp = conn.setSavePoint();
conn.rollback(sp);
–注意,回到回滚点后,回滚点之前的代码虽然没被回滚但是也没提交呢,如果想起作用还要做commit操作.
ThreadLocal – 线程本地变量
TransactionManager中的Connection如果管理br> 如果所有的线程都使用同一个Connection 则事务混乱 – 多线程安全问题
1.3.事务的四大特性
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!