过滤器之编码
get方式的解码无法通过request设置。需要增强request。sun公司也知道我们可能对request对象的方法不满意,于是提供了HttpServletRequestWrapper类给我们实现(如果实现HttpServletRequest接口的话,要实现太多的方法了!
类似静态代理的增强request:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;
public class MyRequest extends HttpServletRequestWrapper {
// 静态代理,用来增强HttpServletRequest
// 1.与被增强类实现共同的接口ServletRequest
// 2.代理类中声明一个变量记住被增强对象
// 3.代理类中创建构造方法用来接受被增强类
HttpServletRequest httpServletRequest;
public MyRequest(HttpServletRequest httpServletRequest ){
super(httpServletRequest);
this.httpServletRequest=httpServletRequest;
}
@Override
public String getParameter(String name) {
// 操作httpServletRequest,覆盖要增强的方法
String strname=httpServletRequest.getParameter("name");
if(strname == null)
return null;
// 不是get请求,=按照原来方法执行
if( httpServletRequest.getMethod() != "get")
return strname;
// get方法 ISO8859-1为tomcat编码
try {
return new String(strname.getBytes("ISO8859-1"),httpServletRequest.getCharacterEncoding());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
编写过滤器:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/fliter")
public class FilterEncode implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// get方法无法通过设置request.setCharacterEncoding();改变编码,
// 因此可以通过增强getParameter()方式来改变编码
// 静态代理类 MyRequest
HttpServletRequest request=(HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse) servletResponse;
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 增强request
MyRequest myRequest = new MyRequest(request);
// 将增强的request放行
filterChain.doFilter(myRequest,response);
}
@Override
public void destroy() {
}
}
动态代理设置过滤器:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response=(HttpServletResponse) servletResponse;
HttpServletRequest request=(HttpServletRequest) servletRequest;
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
filterChain.doFilter((HttpServletRequest)Proxy.newProxyInstance(DynamicFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
@Override
// 会拦截代理对象的任何方法 对request方法增强
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("zhixinginvoke");
if( ! method.getName().equals("getParameter"))
return method.invoke(request,args);
if( ! request.getMethod().equalsIgnoreCase( "get"))
return method.invoke(request,args);
// 执行到这只能是get方法
String name=(String) method.invoke(request,args);
if(name == null)
return null;
return new String(name.getBytes("ISO8859-1"),"UTF-8");
}
}),response);
System.out.println("动态代理");
}
过滤器之压缩
先介绍GZIPOutputStream的使用
# 将压缩的数据写入ByteArrayOutPutStream中
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
gzipOutputStream.write(bytes);
gzipOutputStream.flush();
- 通常情况下servlet中,一般使用getOutPutStream获取ServletOutputStream对象 ,或者通过getWriter获得Printwriter对象,在再过write()将数据写在浏览器。
- 为了压缩数据,通过继承HttpServletResponseWrapper来增强getOutputStream(ServletOutputStream getOutputStream())和getWriter (PrintWriter getWriter())方法把数据写在ByteArrayOutputStream
- 同时增强ServletOutputStream的write方法,因为PrintWriter 本身是包装类,本身就能实现将数据写在ByteArrayOutputStream
增强response:
public class MaxServletReposneWrapper extends HttpServletResponseWrapper {
// 增强response 相当于增强response将原本应该输入到浏览器的数据,输入到ByteArrayOutputStream
// 将数据写入ByteArrayOutputStream,并且提供接口,输出,以用来在过滤器中压缩数据
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
HttpServletResponse response ;
PrintWriter printWriter;
MaxServletReposneWrapper(HttpServletResponse response ){
super(response);
this.response=response;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new MaxServletOutPutStream(byteArrayOutputStream);
}
@Override
public PrintWriter getWriter() throws IOException {
System.out.println("pW______");
printWriter=new PrintWriter(new OutputStreamWriter(byteArrayOutputStream,this.response.getCharacterEncoding()));
return printWriter;
}
byte[] getOutBytes(){
try {
//防止数据在缓存中,要刷新一下!
if (printWriter != null) {
printWriter.close();
}
if (byteArrayOutputStream != null) {
System.out.println("bukong");
byteArrayOutputStream.flush();
return byteArrayOutputStream.toByteArray();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
增强 ServletOutStream
public class MaxServletOutPutStream extends ServletOutputStream {
ByteArrayOutputStream byteArrayOutputStream;
MaxServletOutPutStream( ByteArrayOutputStream byteArrayOutputStream){
this.byteArrayOutputStream=byteArrayOutputStream;
}
@Override
public void write(int b) throws IOException {
this.byteArrayOutputStream.write(b);//????? zhong
}
过滤器:
public class ZipFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
MaxServletReposneWrapper myResponse = new MaxServletReposneWrapper(response);
//把被增强的response对象传递进去,目标资源调用write()方法的时候就不会直接把数据写在浏览器上了
filterChain.doFilter(request, myResponse);
//得到目标资源想要返回给浏览器的数据
byte[] bytes = myResponse.getOutBytes();
//输出原来的大小
System.out.println("压缩前:"+bytes.length);
//使用GZIP来压缩资源,再返回给浏览器
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
gzipOutputStream.write(bytes);
gzipOutputStream.flush();
byteArrayOutputStream.flush();
//得到压缩后的数据
byte[] gzip = byteArrayOutputStream.toByteArray();
System.out.println("压缩后:" + gzip.length);
response.setHeader("Content-Disposition", "attachment; filename=chen.zip" );
//还要设置头,告诉浏览器,这是压缩数据!
response.setHeader("content-encoding", "gzip");
response.setContentLength(gzip.length);
response.getOutputStream().write(gzip);
}
@Override
public void destroy() {
}
}
测试:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("fdshfidsuhfidusfhuidsfhuidshdsuifhsd" +
"uifhsduifffffdshfidsuhfidusfhuidsfhuidshdsuif" +
"hsduifhsduifffffdshfidsuhfidusfhuidsfhuidshd" +
"suifhsduifhsduifffffdshfidsuhfidusfhuidsfhuidsh" +
"dsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuids" +
"hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuid" +
"shdsuifhsduifhsduiffdshfidsuhfidusfhuidsfhuids" +
"hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhui" +
"dshdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfh" +
"uidshdsuifhsduifhsduifffffdshfidsuhfidusfhuids" +
"fhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhuid" +
"sfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhui" +
"dsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfh" +
"uidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusf" +
"huidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidus" +
"fhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhfid" +
"usfhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhf" +
"idusfhuidsfhuidshdsuifhsduifhsd" +
"uifffffdshfidsuhfidusfhuidsfhuidshdsuifhsduifhsduifffffff");
}
过滤器之敏感词过滤
增强request:
class MyDirtyRequest extends HttpServletRequestWrapper {
HttpServletRequest request;
//定义一堆敏感词汇
private List<String> list = Arrays.asList("傻b", "尼玛", "操蛋");
public MyDirtyRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String value = this.request.getParameter(name);
if (value == null) {
return null;
}
//遍历list集合,看看获取得到的数据有没有敏感词汇
for (String s : list) {
if (s.equals(value)) {
value = "*****";
}
}
return value ;
}
}
监听器之检测上线人数
- 通过监听session的创建和销毁来,检测上线人数,因此实现HttpSessionListener
- 不用自己创建session和销毁session,因为服务器会自动创建一个session,以及jESSIONID的cookie
- 此cookie的MaxAge为-1,即浏览器关闭后,cookie消失,但是session依然还在服务器,只是无法通过jessionid找出来,因此可以设置session的存活时间,来模拟session的销毁
监听器:
httpSessionEvent.getSession().getServletContext()
public class LSession implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
ServletContext servletContext=httpSessionEvent.getSession().getServletContext();
Integer num=(Integer) servletContext.getAttribute("num");
if(num == null){
servletContext.setAttribute("num",1);
}else{
num++;
servletContext.setAttribute("num",num);
}
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
ServletContext servletContext=httpSessionEvent.getSession().getServletContext();
Integer num =(Integer) servletContext.getAttribute("num");
if(num == null){
servletContext.setAttribute("num",0);
}else{
num--;
servletContext.setAttribute("num",num);
}
}
}
web.xmlj配置监听器和session存活时间
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<listener>
<listener-class>ListenerSession.LSession</listener-class>
</listener>
jsp测试:
在线人数:${num}
新打开浏览器会增加在线人数,关闭不会销毁session,过了session存活时间才会销毁。
关闭在打开,增加人数。
监听器之session扫描器
-
定时扫描session,移除未使用的session
-
因为要移除session【使用invalidate方法】,所以使用容器,保存session
-
定时扫描session,所以要用到Timer
#Timer的使用 # 1.创建Timer # 2.使用timer.schedule(TimerTask,time) # 3.编写自己的TimerTask
-
容器添加session和定时扫描容器中所有的session,这两个动作要做好并发控制,可以设置一个全局的变量lock进行并发控制
-
因为定时器应该在服务器一启动的时候,就应该被创建了。因此还需要监听ServletContext
定时器任务代码:
public class myTask extends TimerTask {
// 此处如果要使用监听器中的list 和 lock 可以通过构造方法引入 因为对象是引用类型,所以相当于操作监听器中的对象
List<HttpSession> list;
Object lock;
myTask(List<HttpSession> list,Object lock){
this.list=list;
this.lock=lock;
}
@Override
public void run() {
synchronized (lock) {
for (HttpSession session : list) {
// 为了测试,session未使用时间写成1min
if (System.currentTimeMillis() - session.getLastAccessedTime() > 60 * 1000) {
session.invalidate();
list.remove(session);
}
}
}
}
}
监听器:
public class LContextSession implements HttpSessionListener, ServletContextListener {
// 服务器已启动就创建容器 因为要频繁的增删改查所以用linkedlist 容器也应该是线程安全的。
List<HttpSession> list= Collections.synchronizedList(new LinkedList<HttpSession>());
private Object lock=1;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
// web引用已启动就添加定时器
Timer timer=new Timer();
// 延迟为0,间隔60秒扫描一次
timer.schedule(new myTask(list,lock),0,60*1000);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
synchronized (lock){
list.add(httpSessionEvent.getSession());
}
System.out.println("session创建了");
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("session 销毁了");
}
}
监听器之踢人小案例
-
要监听哪个方法,就在哪个方法里写操作代码
-
监听session属性的变化。在attributeAdded(HttpSessionBindingEvent sbe) 方法中写操作
-
在此方法中,创建Map,存在ServletContext中,(如果map已存在,直接获取即可),并且把session放到Map中,以用来在servlet中踢人。
//得到Session属性的值 Object o = sbe.getValue(); //判断属性的内容是否是User对象 if (o instanceof User) { User user = (User) o; map.put(user.getUsername(), sbe.getSession()); } //解释:session只有在属性值为User的时候加入map中一次,如果此session再次添加其他类型的属性值,不会再把该session加入到map中
-
写创建session的servlet
-
视图层列出map中的所有session
-
写踢人的servlet:从ServletContext中获取map,从视图层传入,要踢的人的key,从map中移除,并使session无效
https://segmentfault.com/a/1190000013252595