您的位置:首页 > 大数据

大数据正式21

2017-12-09 18:36 190 查看

大数据正式21

过滤器

定义

Filter--过滤器

是Servlet中最实用的技术--JavaEE核心技术之一【Servlet+Filter+Listener】

可以拦截对资源的访问,拦截下来后可以是否允许通过时,在之前或之后做一些额外单位操作,所谓的拦截,其实是将代表请求的request对象和代表Response对象拦截下来;责任链模式【依次拦截、检查、和控制】

一个资源看可以被多个过滤器拦截

一个拦截器也可以拦截多个资源

图解



常见使用场景

基于URL的访问控制权限

全站乱码解决过滤器

自动登录

过滤敏感词

压缩响应

。。。

实现一个过滤器的步骤

写一个类实现Filter接口

public void init(FilterConfig arg0) throws ServletException

初始化方法

public void doFilter(final ServletRequest arg0, ServletResponse arg1,FilterChain arg2) throws IOException, ServletException

最核心的方法,在存活期间,会造成此方法的执行,在里面写逻辑代码即可

public void destroy()

在过滤器被销毁之前调用,实现善后操作

api




package com.peng.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class FilterDemo implements Filter {

public void destroy() {
System.out.println("destory");
}

public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
System.out.println("kernel");
}

public void init(FilterConfig arg0) throws ServletException {
System.out.println("init");
}

}


在web.xml中配置过滤器

<!-- 过滤器 -->
<filter>
<filter-name>FilterDemo</filter-name>
<filter-class>com.peng.filter.FilterDemo</filter-class>
</filter>

<filter-mapping>
<filter-name>FilterDemo</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


filter的生命周期

在web应用启动的时候,会创建出应用中配置的过滤器对象,init方法进行初始化操作,之后一直存活,直到web应用销毁时,Filter跟着被销毁,再销毁之前执行destory方法的逻辑。在存活期间,进行对资源的拦截处理(doFilter方法),可以增加before和after方法,进行处理,一层一层进,一层一层出。

调用过程

如果一个资源被多个过滤器拦截,顺序为【mapping】配置的顺序



和Filter相关的对象

FilterConfig过滤器配置对象

init方法的参数

获取filter初始化参数

获取ServletContext对象

例子

<filter>
<filter-name>FilterDemo</filter-name>
<filter-class>com.peng.filter.FilterDemo</filter-class>
<init-param>
<param-name>key1</param-name>
<param-value>value1</param-value>
</init-param>
<init-param>
<param-name>key2</param-name>
<param-value>value2</param-value>
</init-param>
</filter>

public void init(FilterConfig arg0) throws ServletException {
System.out.println("init");
Enumeration initParameterNames = arg0.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
String name = initParameterNames.nextElement().toString();
System.out.println(name + "~" + arg0.getInitParameter(name));
}
}


执行效果



FilterChain

doFilter函数的参数

代表过滤器链

提供doFilter方法,执行之后的过滤器

public void doFilter(final ServletRequest arg0, ServletResponse arg1,FilterChain arg2) throws IOException, ServletException {
// 过滤具体操作
// 释放资源--责任链模式,进行下一个过滤器执行操作
arg2.doFilter(arg0, arg1);
}


Filter应用

全站乱码解决过滤器

请求乱码

GET方式

解决方案一:获取参数,解决乱码,再放回去

【有问题:Request方法没setParameter方法】



解决方案二:request中的数据包无法改变,只能改变其原始方法

继承【这里不能使用】:对已有对象的改造无效--因为对象是已经生成的,不能new出新的子类对象

可以使用装饰模式装饰request方法【这里能使用】:

【getParameter(String key)】

【getParameterValues()】

【getParameterMap】

package com.easymall.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class EncodingFilter implements Filter {
private String encode = null;

// 初始化过滤器
public void init(FilterConfig arg0) throws ServletException {
// 获取ServletContext对象
ServletContext sc = arg0.getServletContext();
// 获取全局变量之编码
this.encode = sc.getInitParameter("encode");
}

public void doFilter(final ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
// 请求乱码-get、post一起解决
MyServletRequest msr = new MyServletRequest((HttpServletRequest) arg0);
// 响应乱码
arg1.setCharacterEncoding(encode);
arg1.setContentType("text/html;charset=" + encode);
// 释放资源
arg2.doFilter(msr, arg1);
}

// 销毁过滤器方法
public void destroy() {

}

// 内部类装饰
class MyServletRequest extends HttpServletRequestWrapper {
private ServletRequest request = null;
private boolean hasNoteEncode = true;

public MyServletRequest(HttpServletRequest request) {
super(request);
this.request = request;
}

// 改造方法
@Override
public String getParameter(String name) {
return this.getParameterValues(name) == null ? null : this
.getParameterValues(name)[0];
}

// 改造方法
@Override
public Map<String, String[]> getParameterMap() {
try {
// 注:第一次map之后就对了,得处理--加一个标记
@SuppressWarnings("unchecked")
Map<String, String[]> map = request.getParameterMap();
if (hasNoteEncode) {
for (Map.Entry<String, String[]> entry : map.entrySet()) {
String[] values = entry.getValue();
for (int i = 0; i < values.length; i++) {
values[i] = new String(
values[i].getBytes("iso8859-1"), encode);
}
}
hasNoteEncode = false;
}
return map;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

// 改造方法
@Override
public String[] getParameterValues(String name) {
return this.getParameterMap().get(name);
}

}
}


动态代理:通过代理对象来改造,并且通过代理对象访问被代理对象【这里能使用】:

package com.easymall.filter;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class EncodingFilter implements Filter {
private String encode = null;

public void destroy() {

}

public void doFilter(final ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
// 请求乱码-get-- 动态代理
// 将ServletRequest强转为HttpServletRequest
final HttpServletRequest hsr = (HttpServletRequest) arg0;
// get转码---动态代理方法
// 2、创建代理对象【固定】
// 参数一:被代理对象的类加载器。 实现方式:被代理对象.getClass().getClassLoader()
// 参数二:被代理对象的接口数组。 实现方式:被代理对象.getClass().getInterfaces()
// 参数三:处理类【用来增强方法的】
// 增强代码需要写在处理类的 invoke方法中即可
HttpServletRequest obj = (HttpServletRequest) Proxy.newProxyInstance(
hsr.getClass().getClassLoader(), // 获取被代理类类加载器
hsr.getClass().getInterfaces(), // 获取被代理类实现类的接口
new InvocationHandler() {
// 参数一: Object proxy 代理对象。没用
// 参数二: Method method 被代理对象的对应方法
// 参数三: Object[] args 被代理对象对应方法执行时,传递的实参
public Object invoke(Object arg0, Method method,
Object[] arg2) throws Throwable {
// 针对getParameter方法进行增强
if ("getParameter".equals(method.getName())) {
// 获取提交方式
String m = hsr.getMethod();
if ("GET".equalsIgnoreCase(m)) {
// 调用原来的方法
String invoke = (String) method.invoke(hsr,
arg2);
String re = null;
try {
// 转码
re = new String(invoke
.getBytes("iso8859-1"), encode);
} catch (Exception e) {
}
return re;
}
}
return method.invoke(hsr, arg2);
}
});
// 请求乱码-post
arg0.setCharacterEncoding(encode);
// 响应乱码
arg1.setCharacterEncoding(encode);
arg1.setContentType("text/html;charset=" + encode);
// 释放资源
arg2.doFilter(obj, arg1);
}

public void init(FilterConfig arg0) throws ServletException {
ServletContext sc = arg0.getServletContext();
this.encode = sc.getInitParameter("encode");
}

}


POST方式

arg0.setCharacterEncoding(encode);


响应乱码

解决方案

arg1.setCharacterEncoding(encode);
arg1.setContentType("text/html;charset=" + encode);


自动登录

不加过滤器的登录



加入过滤器的登录



在处理用户登录时

首次登录时:判断是否勾选过自动登录

否--进入登录页面

是--保存到cookie【注意:密码的保密性】

再次访问时:

用户未登录+cookie信息账号密码正确-->>自动登录

已经登录过,判断账号密码是否正确-->>正确则进行登录

代码示例

package com.easymall.filter;

import java.io.IOException;
import java.net.URLDecoder;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.easymall.domain.User;
import com.easymall.factory.BasicFactory;
import com.easymall.service.UserService;

public class AautologinFilter implements Filter {

public void destroy() {

}

public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
// 只有未登录的用户
if (request.getSession(false) == null
|| request.getSession().getAttribute("user") == null) {
// 只有携带Cookie才自动登录
Cookie[] cookies = request.getCookies();
Cookie autoCookie = null;
for (Cookie cookie : cookies) {
if ("autologin".equals(cookie.getName())) {
autoCookie = cookie;
}
}
if (autoCookie != null) {
// 只有自动登录cookie保存的用户名正确才能自动登录
String username = URLDecoder.decode(autoCookie.getValue()
.split("#")[0], "utf-8");
String password = autoCookie.getValue().split("#")[1];
UserService userService = BasicFactory.getFactory().getObj(
UserService.class);
if (userService.checkUsernameAndPassord(username, password)) {
// 获取session
HttpSession session = request.getSession();
// 在session中加入相应的标记
session.setAttribute("user", new User(-1, username, null,
null, null));
// 回到主页
response.getWriter().write("登录成功!正在跳转。。。");
response.setHeader("refresh",
"2;url=" + request.getContextPath() + "/index.jsp");
}
}
} else {// 已经登录过
// 跳转页面的话,会一直进过滤器哦。。。。
}
// 放行资源
arg2.doFilter(arg0, arg1);
}

public void init(FilterConfig arg0) throws ServletException {

}

}


加密

MD5加密算法

特点

任意大小的二进制经过MD5计算得到一个独一无二的128位二进制

相同的数据得到的MD5得到的结果相同

不相同的数据得到的MD5得到的结果不同

通常转化为16进制的32位数据

数据摘要,数据指纹----之后对比

应用

加密存储数据

文件的完整性

数字签名

。。。

EasyMall中,应该加密的地方

Cookie中自动登录的密码的存储

数据库中存放密码的记录,不应该铭文记录

代码示例

package com.easymall.utils;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Utils {
/**
* 使用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);
// 为了防止不够32位,比如一些短的密码生成的数据可能不够32位,那么为了解决这的问题,在数据的前面进行补0操作
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
}


补充

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: