前面写好了用户登录\注册\添加商品的功能模块.下面写一下对于这些功能模块的相关过滤器---自动登录与权限管理:
一、自动登录:
业务逻辑是这样的:jsp登录页面有个“自动登录选项”,如果登录这勾选了,那么在serlvet程序中则会额外的生成一个保存用户名和密码的cookie,然后每次用户向服务器发送请求时,Filter过滤器都会先判断用户的登录状态(session),如果已经登录那么无需做出受任何操作直接放行,如果没有登录(无session),那么这时体现自动登录功能作用的时候到了,先获取自动登录时创建的cookie,为空则用户没有选择自动登录,直接放行吧。不为空,那么开始判断这个cookie中的用户名和密码是否是正确的,如果正确的则给这个cookie获得的用户信息创建session然后放行。如果cookie是错误的,那么直接把cookie干掉,然后放行。
登录的jsp页面,以及相应的servlet代码我在estore商城案例(二)------登录&添加商品&商品列表(上)写过,可以参考这里。
filter代码:
1 public class AutoFilter implements Filter { 2 3 @Override 4 public void doFilter(ServletRequest req, ServletResponse res, 5 FilterChain chain) throws IOException, ServletException { 6 HttpServletRequest request=(HttpServletRequest) req; 7 HttpServletResponse response=(HttpServletResponse) res; 8 //获得来访者路径,判断路径是否是需要登录后才能操作的页面,若果是则进行登录判断,否者放行 9 //获得路径 10 String path=request.getRequestURI().substring(request.getContextPath().length()); 11 //过滤路径 12 if(path.equals("/login.jsp")||path.equals("/login")||path.equals("/regist")||path.equals("/regist.jsp")||path.equals("/invalidate")) 13 { 14 //这些页面不需要判断登录直接放行 15 chain.doFilter(request, response); 16 return; 17 } 18 else{ 19 //访问的路径是需要帮助完成自动登录的 20 //判断是否已经登录 21 User existUser=(User) request.getSession().getAttribute("existUser"); 22 if(existUser==null) 23 { 24 //说明还没有登录,需要获得cookie老进一步判断 25 Cookie targetCookie=CookieUtils.findTargetCookie(request.getCookies(),"autologin"); 26 if(targetCookie!=null) 27 { 28 //登录的时候选择了自动登录,创建了cookie 29 String username=targetCookie.getValue().split("#")[0]; 30 String password=targetCookie.getValue().split("#")[1]; 31 User user=new User(); 32 user.setUsername(username); 33 user.setPassword(password); 34 //判断cookie的有效性 35 UserService us=new UserServiceImpl(); 36 user=us.loginUser(user); 37 if(user==null) 38 { 39 //cookie有问题,销毁这个cookie 40 Cookie cookie=new Cookie("autologin",""); 41 cookie.setMaxAge(0); 42 cookie.setPath("/"); 43 response.addCookie(cookie); 44 chain.doFilter(request, response); 45 return; 46 } 47 else{ 48 request.getSession().setAttribute("existUser",user); 49 chain.doFilter(request, response); 50 return; 51 52 } 53 54 } 55 56 57 } 58 //其他无需处理的情况直接放行 59 chain.doFilter(request, response); 60 return; 61 } 62 63 }
web.xml中的配置:
<filter>
<filter-name>AutoFilter</filter-name>
<filter-class>web.filter.AutoFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
一个项目中有多个过滤器时要注意配置的顺序,以<filter-mapping>顺序为准。
二、权限管理:
这里我把用户分为两种:普通user、管理员admin;且分别创建user.txt和admin.txt用以保存user有admin所属的专有页面:
首先过得来访者请求路径,如果在上面个的两个txt文件中,则需要对用户身份进行判断(否则直接放行)。然后判断用户是否登录,未登录的则跳转到登录页面。然后获得用户身份,如果是admin且请求的路径也是admin范围内,则放行,否则进行拦截,user用户也这么判断:
filter代码:
1 public class PrivilegesFilter implements Filter { 2 private List adminList = new ArrayList();//保存在txt文件中需要权限访问的路径 3 private List userList = new ArrayList(); 4 @Override 5 public void doFilter(ServletRequest req, ServletResponse res, 6 FilterChain chain) throws IOException, ServletException { 7 HttpServletRequest request= (HttpServletRequest) req; 8 HttpServletResponse response=(HttpServletResponse) res; 9 //获得来访者路径 10 String path=request.getRequestURI().substring(request.getContextPath().length()); 11 //System.out.println("uri="+request.getRequestURI());---- /myestore/index.jsp 12 //System.out.println("path="+request.getContextPath());----/myestore 13 if(adminList.contains(path)||userList.contains(path)) 14 { 15 //符合要求,说明请求资源是需要权限过滤的 16 //判断来访者身份 17 User existUser=(User)request.getSession().getAttribute("existUser"); 18 if(existUser!=null) 19 { 20 if(existUser.getRole().equals("admin")) 21 { 22 //管理员,判断请求的路径 23 if(adminList.contains(path)) 24 { 25 //管理员访问的是管理员所有权限的请求 26 chain.doFilter(request, response); 27 return; 28 } 29 else{ 30 throw new MyRuntimeException("对不起,您当前管理员,没有这个权限..."); 31 } 32 } 33 if(existUser.getRole().equals("user")){ 34 35 //普通用户,判断请求的路径 36 if(userList.contains(path)) 37 { 38 //普通用户访问的是普通用户所有权限的请求 39 chain.doFilter(request, response); 40 return; 41 } 42 else{ 43 throw new MyRuntimeException("对不起,您当前普通用户,没有这个权限..."); 44 } 45 } 46 47 } 48 else{ 49 //没有登录,但是请求的资源需要登录权限,说明要让其先登录,然后在过来 50 request.getRequestDispatcher("/login.jsp").forward(request, response); 51 return; 52 53 } 54 } 55 else{ 56 //不需要权限 57 chain.doFilter(request, response); 58 return; 59 60 } 61 } 62 63 @Override 64 public void init(FilterConfig config) throws ServletException { 65 66 67 //filterConfig.getServletContext() 68 System.out.println("servletcontext="+config.getServletContext()); 69 //磁盘的绝对路径 70 String adminfile=PrivilegesFilter.class.getClassLoader().getResource("/admin.txt").getFile(); 71 String userfile=PrivilegesFilter.class.getClassLoader().getResource("/user.txt").getFile(); 72 73 System.out.println("admin="+adminfile+"=====user="+userfile); 74 try { 75 BufferedReader adminReader=new BufferedReader(new FileReader(adminfile)); 76 String line1; 77 while((line1=adminReader.readLine())!=null) 78 { 79 adminList.add(line1); 80 81 } 82 adminReader.close(); 83 BufferedReader userReader=new BufferedReader(new FileReader(userfile)); 84 String line2; 85 while((line2=userReader.readLine())!=null) 86 { 87 userList.add(line2); 88 } 89 userReader.close(); 90 } catch (IOException e) { 91 92 e.printStackTrace(); 93 } 94 95 96 }
xml配置:
<filter>
<filter-name>PrivilegesFilter</filter-name>
<filter-class>web.filter.PrivilegesFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrivilegesFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这个权限配置filter-mapping要放在上面自动登录过滤器的下面。因为在判断权限是要获得用户登录状态的,所以这里两个filter的执行顺序:自动登录→权限登录。
这两块功能就全ok了。
下面写一下给dao层解耦的factory工厂。原理很简单,利用反射,在properties文件中配置对应的dao(接口)名(key)与包含包名的daoimpl名(key)。然后在工厂中传入dao类,然后通过dao名(key),从properties中获得对应的value,然后加加载这个daoimpl类即可:
1 public class DaoFactory { 2 private DaoFactory(){}; 3 private static DaoFactory instance=new DaoFactory(); 4 public static DaoFactory getInstance() 5 { 6 return instance; 7 } 8 public<T> T createDao(Class<T>clazz) 9 { 10 String simpleName=clazz.getSimpleName(); 11 String value = ResourceBundle.getBundle("dao").getString(simpleName); 12 try { 13 return (T) Class.forName(value).newInstance(); 14 } catch (Exception e) { 15 16 e.printStackTrace(); 17 throw new MyRuntimeException(e); 18 } 19 } 20 }
撸完收工,剩余的两个模块也尽量早些撸出来。。。。。。