java Servlet技术中Filter可以实现对请求的统一预处理,使请求有统一的可以控制的入口和出口,用Filter可以轻松解决全站的乱码问题:
request.setCharacterEncoding(charset); //post get
response.setCharacterEncoding(charset);
response.setContentType("text/html;charset=" + charset); //设置在Filter参数中
对动态资源加禁止缓冲头:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
对静态资源加缓存头:
//1.获取到用户想访问的资源
String uri = request.getRequestURI();
//2.获取该资源的缓存时间
int expires = 0;
if(uri.endsWith(".jpg")){
expires = Integer.parseInt(this.config.getInitParameter("jpg"));
}else if(uri.endsWith(".css")){
expires = Integer.parseInt(this.config.getInitParameter("css"));
}else{
expires = Integer.parseInt(this.config.getInitParameter("js"));
}
response.setDateHeader("expires", System.currentTimeMillis()+expires*60*1000);
及实现数据压缩发生等
使用Filter实现用户自动登录是Fiter能轻松实现的一项非常重要的功能,实现如下:
1.用户登录时选择是否要自动登录:
<input name="autoLogin" type="checkbox" value="true" checked/>自动登录
2.servlet处理用户登录请求,如果选择自动登录,则发送一个可以实现自动登录的Cookie:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String name = request.getParameter("name");
String password = request.getParameter("password");
if (name.trim().equals("") || password.trim().equals("")) {
request.getSession().setAttribute("login_message", "用户名或密码不能为空");
response.sendRedirect(request.getContextPath() + "/servlet/login");
return;
}
User user = new BusinessServiceImpl().login(name, password);
if (user == null) {
request.setAttribute("login_message", "用户名或密码不正确");
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return;
}
request.getSession().setAttribute("user", user);
request.setAttribute("message", "登录成功");
//添加自动登录cookie
if (request.getParameter("autoLogin") != null && request.getParameter("autoLogin").equals("true")) {
Cookie cookie = generateCookie(user);
response.addCookie(cookie);
}
request.getRequestDispatcher("/message.jsp").forward(request, response);
} catch (Exception e) {
request.setAttribute("message", "未知错误");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
}
private static Cookie generateCookie(User user) throws NoSuchAlgorithmException {
String name = user.getName();
String password = user.getPassword();
//测试,设置cookie有效其为60s
int time = 60;
//保存到时间
long holdTime = System.currentTimeMillis() + time * 1000;
String fixedValue = "hao";
//cookie的值要包含唯一用户名与密码,以防止其他人生成用户cookie,并且要有cookie保留到的时间,以在自动登录时检查是否cookie是否过期
//必须要生成数据摘要以防止cookie被篡改(如改holdTime),由于服务端可以由唯一用户名来得到用户密码,而密码明文传输不安全,
//所以可以将密码,与要进行摘要的字段组合进行数据摘要,为了提高数据摘要破译的难度,可以在最后加一个只有服务端知道的固定值
//生成数据摘要后要以文本传输,所以还要用Base64编码
String value = name + "_" + holdTime + "_" + Base64.encode(MessageDigest.getInstance("md5").digest((password + ":" + holdTime + ":" + fixedValue).getBytes()));
Cookie cookie = new Cookie("autoLogin", value);
//设置cookie在客户端保留的时间,时间被篡改也没事,因为根本就不是这个时间决定到什么时候可以自动登录的
cookie.setMaxAge(time);
//设置cookie的访问域,域名以.开头(.google.com),表示该cookie对指定域名系统(DNS)区域中的服务器可见(例如www.google.com,但不是a.b.google.com)。默认情况下,Cookie只会返回给发送它们的服务器。
//cookie.setDomain()由于测试时localhost非DNS域,这里不设置
//设置cookie的路径,以/开头,默认是发送cookie的servlet的所在路径,这里设为根路径,域下的所有路径被访问时客户都会回传该cookie
cookie.setPath("/");
//设置是否只在https时请求时发该cookie,默认false
cookie.setSecure(false);
//设置cookie只能在http请求时发,HttpOnly Cookie不应该暴露给客户端脚本代码,因此可能有助于缓解某些类型的跨站点脚本攻击。
cookie.setHttpOnly(true);
//setComment()指定描述cookie用途的注释。如果浏览器向用户显示cookie就设置
//setVersion()设置此Cookie的Cookie协议版本。默认为0,版本0符合最初的Netscape cookie规范,版本1符合RFC 2109。由于RFC 2109仍然太新,因此将版本1视为试验; 请勿在生产网站上使用它。
return cookie;
}
3.在Filter中检测是否有该Cookie,及是否有效,有效就允许登录(保存用户到Session域中):
public class AutoLoginFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute("user") != null) {
chain.doFilter(request, response);
return;
}
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("autoLogin")) {
String value = cookie.getValue();
User user = valid(value);
if (user != null) {
request.getSession().setAttribute("user", user);
}
break;
}
}
}
chain.doFilter(request, response);
}
private User valid(String value) {
try {
String[] fields = value.split("\\_");
User user = new UserDaoXmlImpl().findUser(fields[0]);
String password = user.getPassword();
String holdTime = fields[1];
if (Long.valueOf(holdTime) < System.currentTimeMillis()) {
return null;
}
String fixedValue = "hao";
String md5 = Base64.encode(MessageDigest.getInstance("md5").digest((password + ":" + holdTime + ":" + fixedValue).getBytes()));
if (fields[2].equals(md5)) {
return user;
}
} catch (Exception e) {
//这里正常是没有异常的,有的话表示有坏人改了cookie的值,如改为空则有空指针,数组越界
}
return null;
}
@Override
public void init(FilterConfig config) throws ServletException {
}
@Override
public void destroy() {
}
}
并在web.xml中配置该Filter:
<filter>
<description>自动登陆</description>
<filter-name>autoLogin</filter-name>
<filter-class>com.hao.web.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>autoLogin</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
4.如果用户要注销,则提示客户端把Cookie删除:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession().setAttribute("user",null);
//提示客户端把cookie删除
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
String name = cookie.getName();
if (name.equals("autoLogin")){
Cookie autoLogin = new Cookie("autoLogin", "");
autoLogin.setMaxAge(0);
autoLogin.setPath("/");
response.addCookie(autoLogin);
break;
}
}
}
request.setAttribute("message","注销成功,三秒后自动跳到首页,没有跳转请点击<a href='/"+request.getContextPath()+"'>首页</a><meta http-equiv='refresh' content='3;url=/"+ request.getContextPath()+"'/>");
request.getRequestDispatcher("/message.jsp").forward(request,response);
}
that's all.