一、统一全站字符编码
通过配置参数encoding指明使用何种字符编码,以处理html form请求参数的中文问题。
CharacterEncodingFilter.java
package cn.itcast.web.filter;
//解决全站乱码
import java.io.IOException;
import java.nio.charset.Charset;
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 CharacterEncodingFilter implements Filter {
private FilterConfig FilterConfig = null;
private String defaultCharset = "UTF-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.FilterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String charset = FilterConfig.getInitParameter("charset");
if(charset == null){
//如果为空,则表示没有配置编码,使用默认的编码
charset = defaultCharset;
}
request.setCharacterEncoding(charset);//这样设置只对post方式有效
response.setCharacterEncoding(charset);
response.setContentType("text/html;charset=" + charset);
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
配置:web.xml
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>cn.itcast.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
二、禁止浏览器缓存所有动态页面的过滤器
- 有3个http响应头字段都可以禁止浏览器缓存当前页面,它们在Servlet中的示例代码如下:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Prama","no-cache");
并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头。
- Expires数据头:值为GMT时间值,为-1指浏览器不要缓存页面
- Cache-Control响应头有两个常用值:
- No-cache:浏览器不要缓存当前页面
- Max-age:xxx指浏览器缓存页面xxx秒
示例:
NoCacheFilter.java
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
response.setDateHeader("Expires", -1);
response.setHeader("cache-control", "no-cache");
response.setHeader("Pragma", "no-cache");
chain.doFilter(request, response);
}
配置:
<filter>
<filter-name>NoCacheFilter</filter-name>
<filter-class>cn.itcast.web.filter.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<servlet-name>*.jsp</servlet-name>
</filter-mapping>
说明:这里我们不让jsp进行缓存,所以配置的是*.jsp
。还有,要注意首先要将请求和响应对象进行转换。
三、控制浏览器缓存页面中的静态资源的过滤器
页面中的有些资源是很长时间不变的,比如一些图片或是一些js和css文件,我们可以通过缓存这些资源以提高服务器的性能。
ExpiresFilter.java
package cn.itcast.web.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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ExpiresFilter implements Filter {
private FilterConfig filterConfig = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//1.获取用户想访问的资源
String uri = request.getRequestURI();
//2.得到用户想访问的资源的后缀名
String ext = uri.substring(uri.lastIndexOf(".") + 1);
//3.得到资源需要缓存的时间
String time = filterConfig.getInitParameter(ext);
if(time != null){
long t = Long.parseLong(time)*3600*1000;
response.setDateHeader("expires", System.currentTimeMillis() + t);//注意:这里一定要是一个long型时间值
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
配置
<filter>
<filter-name>ExpiresFilter</filter-name>
<filter-class>cn.itcast.web.filter.ExpiresFilter</filter-class>
<init-param>
<param-name>css</param-name>
<param-value>4</param-value>
</init-param>
<init-param>
<param-name>jpg</param-name>
<param-value>4</param-value>
</init-param>
<init-param>
<param-name>js</param-name>
<param-value>4</param-value>
</init-param>
</filter>
<filter-mapping><!--一个filter对应多个filter-mapping-->
<filter-name>ExpiresFilter</filter-name>
<url-pattern>*.jpg</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>ExpiresFilter</filter-name>
<url-pattern>*.css</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>ExpiresFilter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
说明:从上面的例子中可以看到我们可以精确配置一些静态资源缓存活的时间。如果想看到效果,在试验的时候可以先在IE浏览器中清除缓存,Internet选项-->删除(将最上面的保留收藏夹网站…的勾去掉)-->删除,然后设置-查看文件可以看到目录中的缓存内容
,对于我们想要缓存的内容我们可以查看其有效时间是否和我们设置的一样。
四、保护执行敏感操作servlet
在实际开发中我们经常把一些执行敏感操作的Servlet映射到一些特殊目录中,并用Filter把这些特殊目录保护起来,限制只能拥有相应的访问权限的用户才能访问这些目录下的资源。从而在我们系统中实现一种URL级别的权限功能。
要求:为使Filter具有通用性,Filter保护的资源和相应的访问权限通过Filter参数的形式予以配置。(以后会讲到,这里提一下)
五、实现用户自动登录的过滤器
在用户登录成功后,发送一个名称为user的cookie给客户端,cookie的值为用户名和md5加密后的密码。
编写一个
AutoLoginFilter
,这个Filter检查用户是否带有名称为user的cookie来,如果有,则调用dao查询cookie的用户名和密码是否和数据库中的匹配,匹配则向session中存入user对象(即用户登录标记),以实现程序完成自动登录。
过滤器:AutoLoginFilter.java
package cn.itcast.web.filter;
import java.io.IOException;
import java.net.CookieStore;
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 cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import cn.itcast.utils.WebUtils;
public class AutoLoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
if(request.getSession().getAttribute("user") != null){//表示已经登录了
chain.doFilter(request, response);
return;
}
//1.得到用户带来的autologin的cookie
String value =null;
Cookie cookies[] = request.getCookies();
for(int i = 0; cookies != null && i < cookies.length; i++){
if(cookies[i].getName().equals("autologin")){
value = cookies[i].getValue();
}
}
//2.得到cookie中的用户名和密码
if(value != null){
String username = value.split("\\.")[0];
String password = value.split("\\.")[1];
//3.调用dao获取用户对应的密码
UserDao dao = new UserDao();
User user = dao.find(username);
String dbpassword = user.getPassword();
//4.检查用户带过来的md5密码和数据库中的密码是否匹配,如果匹配则自动登录
if(password.equals(WebUtils.md5(dbpassword))){
request.getSession().setAttribute("user", user);
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
说明:程序中可以看到我们会在cookie中存入一个名为autologin的标记,其值是用户名和使用md5加密的密码,使用点号分隔。
配置:
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>cn.itcast.web.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
处理登录业务的servlet:LoginServlet.java
package cn.itcast.web.servlet;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sun.misc.BASE64Encoder;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import cn.itcast.utils.WebUtils;
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDao dao = new UserDao();
User user = dao.find(username, password);
if(user == null){
request.setAttribute("message", "用户名或密码不对!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return ;
}
request.getSession().setAttribute("user", user);//对session作一个标记
request.setAttribute("message", "登录成功!!!");
//发送自动登录的cookie
sendAutoLoginCookie(request,response,user);
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
private void sendAutoLoginCookie(HttpServletRequest request, HttpServletResponse response, User user) {
int logintime = Integer.parseInt(request.getParameter("logintime"));//得到时间值
Cookie cookie = new Cookie("autologin", user.getUsername() + "." + WebUtils.md5(user.getPassword()));//使用点号进行分割,而BASE64中是没有点号的
cookie.setMaxAge(logintime);//设置cookie的有效时间
cookie.setPath("/day18");//设置cookie的有效路径,即day18的所有cookie
response.addCookie(cookie);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
dao层:UserDao.java
package cn.itcast.dao;
import java.util.List;
import cn.itcast.db.MyDb;
import cn.itcast.domain.User;
public class UserDao {
public User find(String username, String password){
List<User> list = MyDb.getAll();
for(User user : list){
if(user.getUsername().equals(username) && user.getPassword().equals(password)){
return user;
}
}
return null;
}
public User find(String username){
List<User> list = MyDb.getAll();
for(User user : list){
if(user.getUsername().equals(username)){
return user;
}
}
return null;
}
}
模拟一个数据库:MyDb.java
package cn.itcast.db;
import java.util.ArrayList;
import java.util.List;
import cn.itcast.domain.User;
public class MyDb {
private static List list = new ArrayList();
static {
list.add(new User("aaa","111"));
list.add(new User("bbb","222"));
list.add(new User("ccc","333"));
}
public static List getAll(){
return list;
}
}
实体类:User.java
package cn.itcast.domain;
public class User {
private String username ;
private String password ;
public User() {
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
工具类:WebUtils.java
package cn.itcast.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Encoder;
public class WebUtils {
public static String md5(String message){
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte result[] = md.digest(message.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(result);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
界面:login.jsp
<form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
有效期:
<input type="radio" name="logintime" value="3600">1小时
<input type="radio" name="logintime" value="${10*60}">10分钟
<input type="radio" name="logintime" value="${5*60}">5分钟
<br/>
<input type="submit" value="登录">
</form>
index.jsp
欢迎你:${user.username }登录
全局消息显示页面:message.jsp
${message}
说明:
试验的时候我们先访问
login.jsp
进行登录,此时请求经过filter时没有经过任何处理就直接到达了servlet,servlet将提交过的用户名和密码和数据库中数据进行对比,如果有此用户则将此用户存入session,就表示此用户已经登录了。然后再访问
index.jsp
,此时经过filter的时候filter发现session中已经有此用户,则直接提交给servlet。上面是在一次会话中进行的试验,此时我们将浏览器关闭,再次访问
index.jsp
,此时请求经过过滤器时,过滤器会发现cookie中存在一个autologin的标记,则让此用户自动登录。这是因为用户第一次登录的时候我们的servlet会向cookie中存入一个autologin的标记,只要我们下次登录在我们设置的缓存保存时间之内就会自动登录。