一、統(tǒng)一全站字符編碼
通過配置參數(shù)encoding指明使用何種字符編碼,以處理html form請(qǐng)求參數(shù)的中文問題。
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){
//如果為空,則表示沒有配置編碼,使用默認(rèn)的編碼
charset = defaultCharset;
}
request.setCharacterEncoding(charset);//這樣設(shè)置只對(duì)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>
二、禁止瀏覽器緩存所有動(dòng)態(tài)頁面的過濾器
- 有3個(gè)http響應(yīng)頭字段都可以禁止瀏覽器緩存當(dāng)前頁面,它們?cè)赟ervlet中的示例代碼如下:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Prama","no-cache");
并不是所有的瀏覽器都能完全支持上面的三個(gè)響應(yīng)頭,因此最好是同時(shí)使用上面的三個(gè)響應(yīng)頭。
- Expires數(shù)據(jù)頭:值為GMT時(shí)間值,為-1指瀏覽器不要緩存頁面
- Cache-Control響應(yīng)頭有兩個(gè)常用值:
- No-cache:瀏覽器不要緩存當(dāng)前頁面
- 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進(jìn)行緩存,所以配置的是*.jsp。還有,要注意首先要將請(qǐng)求和響應(yīng)對(duì)象進(jìn)行轉(zhuǎn)換。
三、控制瀏覽器緩存頁面中的靜態(tài)資源的過濾器
頁面中的有些資源是很長(zhǎng)時(shí)間不變的,比如一些圖片或是一些js和css文件,我們可以通過緩存這些資源以提高服務(wù)器的性能。
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.得到資源需要緩存的時(shí)間
String time = filterConfig.getInitParameter(ext);
if(time != null){
long t = Long.parseLong(time)*3600*1000;
response.setDateHeader("expires", System.currentTimeMillis() + t);//注意:這里一定要是一個(gè)long型時(shí)間值
}
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><!--一個(gè)filter對(duì)應(yīng)多個(gè)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>
說明:從上面的例子中可以看到我們可以精確配置一些靜態(tài)資源緩存活的時(shí)間。如果想看到效果,在試驗(yàn)的時(shí)候可以先在IE瀏覽器中清除緩存,Internet選項(xiàng)-->刪除(將最上面的保留收藏夾網(wǎng)站…的勾去掉)-->刪除,然后設(shè)置-查看文件可以看到目錄中的緩存內(nèi)容,對(duì)于我們想要緩存的內(nèi)容我們可以查看其有效時(shí)間是否和我們?cè)O(shè)置的一樣。
四、保護(hù)執(zhí)行敏感操作servlet
在實(shí)際開發(fā)中我們經(jīng)常把一些執(zhí)行敏感操作的Servlet映射到一些特殊目錄中,并用Filter把這些特殊目錄保護(hù)起來,限制只能擁有相應(yīng)的訪問權(quán)限的用戶才能訪問這些目錄下的資源。從而在我們系統(tǒng)中實(shí)現(xiàn)一種URL級(jí)別的權(quán)限功能。
要求:為使Filter具有通用性,F(xiàn)ilter保護(hù)的資源和相應(yīng)的訪問權(quán)限通過Filter參數(shù)的形式予以配置。(以后會(huì)講到,這里提一下)
五、實(shí)現(xiàn)用戶自動(dòng)登錄的過濾器
在用戶登錄成功后,發(fā)送一個(gè)名稱為user的cookie給客戶端,cookie的值為用戶名和md5加密后的密碼。
編寫一個(gè)
AutoLoginFilter,這個(gè)Filter檢查用戶是否帶有名稱為user的cookie來,如果有,則調(diào)用dao查詢cookie的用戶名和密碼是否和數(shù)據(jù)庫中的匹配,匹配則向session中存入user對(duì)象(即用戶登錄標(biāo)記),以實(shí)現(xiàn)程序完成自動(dòng)登錄。
過濾器: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){//表示已經(jīng)登錄了
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.調(diào)用dao獲取用戶對(duì)應(yīng)的密碼
UserDao dao = new UserDao();
User user = dao.find(username);
String dbpassword = user.getPassword();
//4.檢查用戶帶過來的md5密碼和數(shù)據(jù)庫中的密碼是否匹配,如果匹配則自動(dòng)登錄
if(password.equals(WebUtils.md5(dbpassword))){
request.getSession().setAttribute("user", user);
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
說明:程序中可以看到我們會(huì)在cookie中存入一個(gè)名為autologin的標(biāo)記,其值是用戶名和使用md5加密的密碼,使用點(diǎn)號(hào)分隔。
配置:
<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>
處理登錄業(yè)務(wù)的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", "用戶名或密碼不對(duì)?。?);
request.getRequestDispatcher("/message.jsp").forward(request, response);
return ;
}
request.getSession().setAttribute("user", user);//對(duì)session作一個(gè)標(biāo)記
request.setAttribute("message", "登錄成功?。?!");
//發(fā)送自動(dòng)登錄的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"));//得到時(shí)間值
Cookie cookie = new Cookie("autologin", user.getUsername() + "." + WebUtils.md5(user.getPassword()));//使用點(diǎn)號(hào)進(jìn)行分割,而BASE64中是沒有點(diǎn)號(hào)的
cookie.setMaxAge(logintime);//設(shè)置cookie的有效時(shí)間
cookie.setPath("/day18");//設(shè)置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;
}
}
模擬一個(gè)數(shù)據(jù)庫: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;
}
}
實(shí)體類: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小時(shí)
<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}
說明:
試驗(yàn)的時(shí)候我們先訪問
login.jsp進(jìn)行登錄,此時(shí)請(qǐng)求經(jīng)過filter時(shí)沒有經(jīng)過任何處理就直接到達(dá)了servlet,servlet將提交過的用戶名和密碼和數(shù)據(jù)庫中數(shù)據(jù)進(jìn)行對(duì)比,如果有此用戶則將此用戶存入session,就表示此用戶已經(jīng)登錄了。然后再訪問
index.jsp,此時(shí)經(jīng)過filter的時(shí)候filter發(fā)現(xiàn)session中已經(jīng)有此用戶,則直接提交給servlet。上面是在一次會(huì)話中進(jìn)行的試驗(yàn),此時(shí)我們將瀏覽器關(guān)閉,再次訪問
index.jsp,此時(shí)請(qǐng)求經(jīng)過過濾器時(shí),過濾器會(huì)發(fā)現(xiàn)cookie中存在一個(gè)autologin的標(biāo)記,則讓此用戶自動(dòng)登錄。這是因?yàn)橛脩舻谝淮蔚卿浀臅r(shí)候我們的servlet會(huì)向cookie中存入一個(gè)autologin的標(biāo)記,只要我們下次登錄在我們?cè)O(shè)置的緩存保存時(shí)間之內(nèi)就會(huì)自動(dòng)登錄。